home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / 80X86 / ASMTUT.ZIP / ASMTUT.TXT
Encoding:
Text File  |  1996-04-26  |  73.6 KB  |  3,889 lines

  1. =====================================================================
  2.  
  3. ...  GAVIN'S GUIDE TO 80x86 ASSEMBLY
  4.  
  5. =====================================================================
  6.  
  7. .Copyright (c) Gavin Estey, 1995. All rights reserved.
  8.  
  9.  
  10. This was originally written for the Game Developer's Magazine and 
  11.  
  12. after getting lots of positive feedback I added and expanded it. I 
  13.  
  14. have spent a lot of time working on it and I would appreciate 
  15.  
  16. hearing from you if you like it.
  17.  
  18.  
  19. If you want to contact me then email me at:
  20.  
  21.  
  22.     gavin@senator.demon.co.uk or on CompuServe 100767,1325    
  23.  
  24.   
  25.  
  26.  
  27. RESOURCES THAT WOULD BE USEFUL
  28.  
  29. ---------------------------------------------------------------------
  30.  
  31.  
  32. There are several resources that you may find useful:
  33.  
  34.  
  35. List of Instructions and timings:
  36.  
  37.  
  38. If you have TASM then the "Borland Turbo Assembler Quick Reference" 
  39.  
  40. has a list of instructions and timings up to 486. The "Intel Pentium 
  41.  
  42. Family User's Manual: Volume 3" is equally useful.
  43.  
  44.  
  45. List of Interrupts:
  46.  
  47.  
  48. There are several books that have this information but the most up to
  49.  
  50. date is Ralf Brown's Interrupt list available freely in four parts at
  51.  
  52. ftp://x2ftp.oulu.fi/pub/msdos/programming/docs/interXX[a-d].zip where
  53.  
  54. XX is the version.
  55.  
  56.  
  57. A book that covers both these topics and is a useful assembly
  58.  
  59. reference is "The Revolutionary guide to Assembly Language",
  60.  
  61. ISBN 1-874416-12-5 publised by WROX Press.
  62.  
  63.   
  64.  
  65. OVERVIEW OF THE 80x86 FAMILY 
  66.  
  67. ---------------------------------------------------------------------
  68.  
  69.  
  70. The 80x86 family was first started in 1981 with the 8086 and the 
  71.  
  72. newest member is the Pentium which was released thirteen years later 
  73.  
  74. in 1994. They are all backwards compatible with each other but each 
  75.  
  76. new generation has added features and more speed than the previous 
  77.  
  78. chip. Today there are very few computers in use that have the 8088 
  79.  
  80. and 8086 chips in them as they are very outdated and slow. There are 
  81.  
  82. a few 286's but their numbers are declining as today's software 
  83.  
  84. becomes more and more demanding. Even the 386, Intel's first 32-bit 
  85.  
  86. CPU, is now declining and it seems that the 486 is now the entry 
  87.  
  88. level system. 
  89.  
  90.  
  91. Representation of numbers in binary
  92.  
  93. ---------------------------------------------------------------------
  94.  
  95.  
  96. Before we begin to understand how to program in assembly it is best 
  97.  
  98. to try to understand how numbers are represented in computers. 
  99.  
  100. Numbers are stored in binary, base two. There are several terms which 
  101.  
  102. are used to describe different size numbers and I will describe 
  103.  
  104. what these mean. 
  105.  
  106.  
  107. 1 BIT:          0
  108.  
  109.  
  110. One bit is the simplest piece of data that exists.  Its either a one 
  111.  
  112. or a zero. 
  113.  
  114.  
  115. 1 NIBBLE:       0000
  116.  
  117. 4 BITS
  118.  
  119.  
  120. The nibble is four bits or half a byte. Note that it has a maximum 
  121.  
  122. value of 15 (1111 = 15). This is the basis for the hexadecimal (base 
  123.  
  124. 16) number system which is used as it is far easier to understand. 
  125.  
  126. Hexadecimal numbers go from 1 to F and are followed by a h to 
  127.  
  128. state that the are in hex. i.e. Fh = 15 decimal. Hexadecimal numbers 
  129.  
  130. that begin with a letter are prefixed with a 0 (zero).
  131.  
  132.  
  133. 1 BYTE          00000000
  134.  
  135. 2 NIBBLES
  136.  
  137. 8 BITS
  138.  
  139.  
  140. A byte is 8 bits or 2 nibbles. A byte has a maximum value of FFh 
  141.  
  142. (255 decimal). Because a byte is 2 nibbles the hexadecimal 
  143.  
  144. representation is two hex digits in a row i.e. 3Dh. The byte is also 
  145.  
  146. that size of the 8-bit registers which we will be covering later.
  147.  
  148.  
  149. 1  WORD         0000000000000000
  150.  
  151. 2  BYTES
  152.  
  153. 4  NIBBLES 
  154.  
  155. 16 BITS
  156.  
  157.  
  158. A word is two bytes that are stuck together.  A word has a maximum 
  159.  
  160. value of FFFFh (65,536).  Since a word is four nibbles, it is 
  161.  
  162. represented by four hex digits.  This is the size of the 16-bit 
  163.  
  164. registers.
  165.  
  166.  
  167. Registers
  168.  
  169. ---------------------------------------------------------------------
  170.  
  171.  
  172. Registers are a place in the CPU where a number can be stored and 
  173.  
  174. manipulated. There are three sizes of registers: 8-bit, 16-bit and 
  175.  
  176. on 386 and above 32-bit. There are four different types of 
  177.  
  178. registers; general purpose registers, segment registers, index 
  179.  
  180. registers and stack registers. Firstly here are descriptions of the 
  181.  
  182. main registers. Stack registers and segment registers will be 
  183.  
  184. covered later. 
  185.  
  186.  
  187. General Purpose Registers
  188.  
  189. ---------------------------------------------------------------------
  190.  
  191.  
  192. These are 16-bit registers. There are four general purpose registers;
  193.  
  194. AX, BX, CX and DX. They are split up into 8-bit registers. AX is split
  195.  
  196. up into AH which contains the high byte and AL which contains the low
  197.  
  198. byte. On 386's and above there are also 32-bit registers, these have
  199.  
  200. the same names as the 16-bit registers but with an 'E' in front i.e.
  201.  
  202. EAX. You can use AL, AH, AX and EAX separatly and treat them as
  203.  
  204. separate registers for some tasks.
  205.  
  206.  
  207. If AX contained 24689 decimal:
  208.  
  209.                         
  210.  
  211.                    AH        AL   
  212.  
  213.                 01100000  01110001
  214.  
  215.  
  216. AH would be 96 and AL would be 113. If you added one to AL it would
  217.  
  218. be 114 and AH would be unchanged. 
  219.  
  220.  
  221. SI, DI, SP and BP can also be used as general purpose registers but
  222.  
  223. have more specific uses. They are not split into two halves.
  224.  
  225.  
  226. Index Registers
  227.  
  228. ---------------------------------------------------------------------
  229.  
  230.  
  231. These are sometimes called pointer registers and they are 16-bit 
  232.  
  233. registers. They are mainly used for string instructions. There are 
  234.  
  235. three index registers SI (source index), DI (destination index) and 
  236.  
  237. IP (instruction pointer). On 386's and above there are also 32-bit 
  238.  
  239. index registers: EDI and ESI. You can also use BX to index strings.
  240.  
  241. IP is a index register but it can't be manipulated directly as it
  242.  
  243. stores the address of the next instruction. 
  244.  
  245.  
  246. Stack registers
  247.  
  248. ---------------------------------------------------------------------
  249.  
  250.  
  251. BP and SP are stack registers and are used when dealing with the 
  252.  
  253. stack. They will be covered when we talk about the stack later on.
  254.  
  255.  
  256. Segments and offsets
  257.  
  258. ---------------------------------------------------------------------
  259.  
  260.  
  261. The original designers of the 8088 decided that nobody will ever 
  262.  
  263. need to use more that one megabyte of memory so they built the chip 
  264.  
  265. so it couldn't access above that. The problem is to access a whole 
  266.  
  267. megabyte 20 bits are needed. Registers only have 16 bits and they 
  268.  
  269. didn't want to use two because that would be 32 bits and they 
  270.  
  271. thought that this would be too much for anyone. They came up with 
  272.  
  273. what they thought was a clever way to solve this problem: segments 
  274.  
  275. and offsets. This is a way to do the addressing with two registers 
  276.  
  277. but not 32 bits.
  278.  
  279.  
  280. OFFSET  = SEGMENT * 16
  281.  
  282. SEGMENT = OFFSET / 16 (the lower 4 bits are lost)
  283.  
  284.  
  285. One register contains the segment and another register contains the 
  286.  
  287. offset. If you put the two registers together you get a 20-bit 
  288.  
  289. address.
  290.  
  291.  
  292. SEGMENT         0010010000010000----
  293.  
  294. OFFSET          ----0100100000100010
  295.  
  296. 20-bit Address  00101000100100100010
  297.  
  298. ..====== DS ======                                              
  299.  
  300. ..     ====== SI ======
  301.  
  302. ..
  303.  
  304. Notice that DS and SI overlap. This is how DS:SI is used to make a 
  305.  
  306. 20 bit address. The segment is in DS and the offset is in SI. The 
  307.  
  308. standard notation for a Segment/Offset pair is: SEGMENT:OFFSET
  309.  
  310.  
  311. Segment registers are: CS, DS, ES, SS. On the 386+ there are also FS 
  312.  
  313. and GS.
  314.  
  315.  
  316. Offset registers  are: BX, DI, SI, BP, SP, IP.  In 386+ protected 
  317.  
  318. mode1, ANY general register (not a segment register) can be used as 
  319.  
  320. an  Offset register. (Except IP, which you can't manipulate 
  321.  
  322. directly).
  323.  
  324.  
  325. If you  are now thinking that assembly must be really hard and you 
  326.  
  327. don't understand segments and offsets at all then don't worry. I 
  328.  
  329. didn't understand them at first but I struggled on and found out 
  330.  
  331. that they were not so hard to use in practice.
  332.  
  333.  
  334. THE STACK
  335.  
  336. ---------------------------------------------------------------------
  337.  
  338.  
  339. As there are only six registers that are used for most operations, 
  340.  
  341. you're probably wondering how do you get around that. It's easy. 
  342.  
  343. There is something called a stack which is an area of memory which 
  344.  
  345. you can save and restore values to.
  346.  
  347.  
  348. This is an area of memory that is like a stack of plates. The last 
  349.  
  350. one you put on is the first one that you take off. This is sometimes 
  351.  
  352. refered to as Last On First Off (LOFO) or First In First Out (LIFO).
  353.  
  354. If another piece of data is put on the stack it grows downwards.
  355.  
  356.  
  357. As you can see the stack starts at a high address and grows 
  358.  
  359. downwards. You have to make sure that you don't put too much data in 
  360.  
  361. the stack or it will overflow.
  362.  
  363.  
  364. AN INTRODUCTION TO ASSEMBLY INSTRUCTIONS
  365.  
  366. ---------------------------------------------------------------------
  367.  
  368.  
  369. There are a lot of instructions in assembly but there are only about 
  370.  
  371. twenty that you have to know and will use very often. Most 
  372.  
  373. instructions are made up of three characters and have an operand then 
  374.  
  375. a comma then another operand. For example to put a data into a 
  376.  
  377. register you use the MOV instruction. 
  378.  
  379.  
  380. .mov ax,10                       ;put 10 into ax
  381.  
  382. .mov bx,20                       ;put 20 into bx
  383.  
  384. .mov cx,30                       ;put 30 into cx
  385.  
  386. .mov dx,40                       ;put 40 into dx
  387.  
  388.  
  389. Notice that in assembler anything after a ; (semicolon) is ignored. 
  390.  
  391. This is very useful for commenting your code.
  392.  
  393.  
  394. PUSH AND POP: TWO INSTRUCTIONS TO USE THE STACK
  395.  
  396. ---------------------------------------------------------------------
  397.  
  398.  
  399. You know about the stack but not how to put data in an out of it. 
  400.  
  401. There are two simple instructions that you need to know: push and 
  402.  
  403. pop. Here is the syntax for their use:
  404.  
  405.  
  406. PUSH    Puts a piece of data onto the top of the stack
  407.  
  408.  
  409. Syntax:
  410.  
  411. .push data
  412.  
  413.  
  414. POP     Puts the piece of data from the top of the stack into a
  415.  
  416.         specified register or variable.
  417.  
  418.  
  419. Syntax:
  420.  
  421. .pop register or variable
  422.  
  423. .
  424.  
  425. This example of code demonstrates how to use the push and pop 
  426.  
  427. instructions
  428.  
  429.  
  430. .push cx                 ;put cx on the stack
  431.  
  432. .push ax                 ;put ax on the stack
  433.  
  434. .pop cx                  ;put value from stack into cx
  435.  
  436. .pop ax                  ;put value from stack into ax
  437.  
  438.  
  439. Notice that the values of CX and AX will be exchanged. There is an
  440.  
  441. instruction to exchange two registers: XCHG, which would reduce the
  442.  
  443. previous fragment to "xchg ax,cx".
  444.  
  445.  
  446. TYPES OF OPERAND 
  447.  
  448. ---------------------------------------------------------------------
  449.  
  450.  
  451. There are three types of operands in assembler: immediate, register 
  452.  
  453. and memory. Immediate is a number which will be known at compilation 
  454.  
  455. and will always be the same for example '20' or 'A'. A register 
  456.  
  457. operand is any general purpose or index register for example AX or 
  458.  
  459. SI. A memory operand is a variable which is stored in memory which 
  460.  
  461. will be covered later.
  462.  
  463.  
  464. SOME INSTRUCTIONS THAT YOU WILL NEED TO KNOW
  465.  
  466. ---------------------------------------------------------------------
  467.  
  468.  
  469. This is a list of some important instructions that you need to know 
  470.  
  471. before you can understand or write assembly programs.
  472.  
  473.  
  474. MOV     moves a value from one place to another.
  475.  
  476.  
  477. Syntax:
  478.  
  479. .MOV destination, source
  480.  
  481.  
  482. for example:
  483.  
  484. .mov ax,10               ;moves an immediate value into ax 
  485.  
  486. .mov bx,cx               ;moves value from cx into bx
  487.  
  488. .mov dx,Number           ;moves the value of Number into dx
  489.  
  490.  
  491. INT     calls a DOS or BIOS function which are subroutines to do 
  492.  
  493.         things that we would rather not write a function for e.g. 
  494.  
  495.         change video mode, open a file etc.
  496.  
  497.  
  498. Syntax:
  499.  
  500. .INT interrupt number
  501.  
  502.  
  503. For example:
  504.  
  505. .int 21h                 ;Calls DOS service
  506.  
  507. .int 10h                 ;Calls the Video BIOS interrupt
  508.  
  509.  
  510. Most interrupts have more than one function, this means that you 
  511.  
  512. have to pass a number to the function you want. This is usually put 
  513.  
  514. in AH. To print a message on the screen all you need to do is this:
  515.  
  516.  
  517. .mov ah,9                ;subroutine number 9
  518.  
  519. .int 21h                 ;call the interrupt
  520.  
  521.  
  522. But first you have to specify what to print. This function needs 
  523.  
  524. DS:DX to be a far pointer to where the string is. The string has to 
  525.  
  526. be terminated with a dollar sign ($). This would be easy if DS could 
  527.  
  528. be manipulated directly, to get round this we have to use AX.
  529.  
  530.  
  531. This example shows how it works:
  532.  
  533. .
  534.  
  535. .mov dx,OFFSET Message   ;DX contains offset of message
  536.  
  537. .mov ax,SEG Message      ;AX contains segment of message
  538.  
  539. .mov ds,ax               ;DS:DX points to message
  540.  
  541. .mov ah,9                ;function 9 - display string
  542.  
  543. .int 21h                 ;call dos service
  544.  
  545.  
  546. The words OFFSET and SEG tell the compiler that you want the 
  547.  
  548. segment or the offset of the message put in the register not the 
  549.  
  550. contents of the message. Now we know how to set up the code to 
  551.  
  552. display the message we need to declare the message. In the data 
  553.  
  554. segment1 we declare the message like this:
  555.  
  556.  
  557. .Message DB "Hello World!$"
  558.  
  559.  
  560. Notice that the string is terminated with an dollar sign. What does 
  561.  
  562. 'DB' mean? DB is short for declare byte and the message is an array 
  563.  
  564. of bytes (an ASCII character takes up one byte). Data can be 
  565.  
  566. declared in a number of sizes: bytes (DB), words (DW) and double 
  567.  
  568. words (DD). You don't have to worry about double words at the moment 
  569.  
  570. as you need a 32-bit register, such as EAX, to fit them in.
  571.  
  572.  
  573. Here are some examples of declaring data:
  574.  
  575. .
  576.  
  577. .Number1 db ?
  578.  
  579. .Number2 dw ?
  580.  
  581.  
  582. The question mark (?) on the end means that the data isn't 
  583.  
  584. initialised i.e. it has no value in to start with. That could as 
  585.  
  586. easily be written as:
  587.  
  588.  
  589. .Number1         db 0
  590.  
  591. .Number2         dw 1
  592.  
  593.  
  594. This time Number1 is equal to 0 and Number2 is equal to 1 when you 
  595.  
  596. program loads. Your program will also be three bytes longer.  If you 
  597.  
  598. declare a variable as a word you cannot move the value of this 
  599.  
  600. variable into a 8-bit register and you can't declare a variable 
  601.  
  602. as a byte and move the value into a 16-bit register. For examples:
  603.  
  604.  
  605. .mov al,Number1          ;ok
  606.  
  607. .mov ax,Number1          ;error
  608.  
  609.  
  610. .mov bx,Number2          ;ok
  611.  
  612. .mov bl,Number2          ;error
  613.  
  614.  
  615. All you have to remember is that you can only put bytes into 8-bit 
  616.  
  617. registers and words into 16-bit registers.
  618.  
  619.  
  620. YOUR FIRST ASSEMBLY PROGRAM
  621.  
  622. ---------------------------------------------------------------------
  623.  
  624.  
  625. Now that you know some basic instructions and a little about data it 
  626.  
  627. is time that we looked at a full assembly program which can be 
  628.  
  629. compiled. 
  630.  
  631.  
  632. Listing 1: 1STPROG.ASM
  633.  
  634.  
  635. ;This is a simple program which displays "Hello World!" on the 
  636.  
  637. ;screen. 
  638.  
  639.  
  640. .model small
  641.  
  642. .stack                  
  643.  
  644. .data           
  645.  
  646.      
  647.  
  648. Message db "Hello World!$"              ;message to be display
  649.  
  650.  
  651. .code           
  652.  
  653. .mov dx,OFFSET Message           ;offset of Message is in DX 
  654.  
  655. .mov ax,SEG Message              ;segment of Message is in AX
  656.  
  657.         mov ds,ax                       ;DS:DX points to string 
  658.  
  659.         mov ah,9                        ;function 9 - display string                 
  660.  
  661.         int 21h                         ;call dos service                 
  662.  
  663.  
  664.         mov ax,4c00h                    ;return to dos DOS 
  665.  
  666.         int 21h      
  667.  
  668. .
  669.  
  670. END start                               ;end here
  671.  
  672.  
  673. COMPILATION INSTRUCTIONS
  674.  
  675. ---------------------------------------------------------------------
  676.  
  677.  
  678. These are some instructions to compile and link programs. If you 
  679.  
  680. have a compiler other than TASM or A86 then see your instruction 
  681.  
  682. manual.
  683.  
  684.  
  685. Turbo Assembler:
  686.  
  687.  
  688. .tasm file.asm
  689.  
  690. .tlink file [/t]
  691.  
  692.  
  693. The /t switch makes a .COM file. This will only work if the memory 
  694.  
  695. model is declared as tiny in the source file.
  696.  
  697.  
  698. A86:
  699.  
  700.  
  701. .a86 file.asm
  702.  
  703.  
  704. This will compile your program to a .COM file. It doesn't matter 
  705.  
  706. what the memory model is.
  707.  
  708.  
  709. SOME INSTRUCTIONS THAT YOU NEED TO KNOW 
  710.  
  711. ---------------------------------------------------------------------
  712.  
  713.  
  714. This is just a list of some basic assembly instructions that are 
  715.  
  716. very important and are used often.
  717.  
  718.  
  719. ADD     Add the contents of one number to another
  720.  
  721.  
  722. Syntax:
  723.  
  724.  
  725. .ADD operand1,operand2
  726.  
  727.  
  728. This adds operand2 to operand1. The answer is stored in operand1. 
  729.  
  730. Immediate data cannot be used as operand1 but can be used as 
  731.  
  732. operand2.
  733.  
  734.  
  735. SUB     Subtract one number from another
  736.  
  737.  
  738. Syntax:
  739.  
  740. .SUB operand1,operand2
  741.  
  742.  
  743. This subtracts operand2 from operand1. Immediate data cannot be used 
  744.  
  745. as operand1 but can be used as operand2.
  746.  
  747.  
  748. MUL     Multiplies two unsigned integers (always positive)
  749.  
  750. IMUL    Multiplies two signed integers (either positive or negitive)
  751.  
  752.  
  753. Syntax: 
  754.  
  755. .MUL register or variable
  756.  
  757. .IMUL register or variable
  758.  
  759.  
  760. This multiples AL or AX by the register or variable given. AL is
  761.  
  762. multiplied if a byte sized operand is given and the result is stored
  763.  
  764. in AX. If the operand is word sized AX is multiplied and the result
  765.  
  766. is placed in DX:AX.
  767.  
  768.  
  769. On a 386, 486 or Pentium the EAX register can be used and the answer 
  770.  
  771. is stored in EDX:EAX.
  772.  
  773.  
  774. DIV     Divides two unsigned integers (always positive)
  775.  
  776. IDIV    Divides two signed integers (either positive or negitive)
  777.  
  778.  
  779. Syntax:
  780.  
  781. .DIV register or variable
  782.  
  783. .IDIV register or variable
  784.  
  785.  
  786. This works in the same way as MUL and IMUL by dividing the number in 
  787.  
  788. AX by the register or variable given. The answer is stored in two 
  789.  
  790. places. AL stores the answer and the remainder is in AH. If the 
  791.  
  792. operand is a 16 bit register than the number in DX:AX is 
  793.  
  794. divided by the operand and the answer is stored in AX and remainder 
  795.  
  796. in DX.
  797.  
  798.  
  799. MAKING THINGS EASIER
  800.  
  801. ---------------------------------------------------------------------
  802.  
  803.  
  804. The way we entered the address of the message we wanted to print was 
  805.  
  806. a bit cumbersome. It took three lines and it isn't the easiest thing 
  807.  
  808. to remember
  809.  
  810.  
  811. .mov dx,OFFSET MyMessage                                         
  812.  
  813. .mov ax,SEG MyMessage                                            
  814.  
  815. .mov ds,ax              
  816.  
  817.  
  818. We can replace all this with just one line. This makes the code 
  819.  
  820. easier to read and it easier to remember.
  821.  
  822.  
  823. .mov dx,OFFSET MyMessage
  824.  
  825.  
  826. To make this work at the beginning of your code add these lines:
  827.  
  828. .
  829.  
  830. .mov ax,@data            
  831.  
  832. .mov ds,ax
  833.  
  834.  
  835. Note: for A86 you need to change the first line to: 
  836.  
  837.  
  838. .mov ax,data
  839.  
  840.  
  841. This is because all the data in the segment has the same SEG value.
  842.  
  843. Putting this in DS saves us reloading this every time we want to
  844.  
  845. use another thing in the same segment.
  846.  
  847.  
  848. KEYBOARD INPUT
  849.  
  850. ---------------------------------------------------------------------
  851.  
  852.  
  853. We are going to use interrupt 16h, function 00h to read the 
  854.  
  855. keyboard. This gets a key from the keyboard buffer.  If there isn't 
  856.  
  857. one, it waits until there is. It returns the SCAN code in AH and the 
  858.  
  859. ASCII translation in AL.
  860.  
  861.  
  862. .xor ah,ah               ;function 00h - get character
  863.  
  864. .int 16h                 ;interrupt 16h
  865.  
  866.  
  867. All we need to worry about for now is the ascii value which is in AL.
  868.  
  869.  
  870. Note: XOR performs a Boolean Exclusive OR. It is commonly used to
  871.  
  872. erase a register or variable.
  873.  
  874.  
  875. PRINTING A CHARACTER
  876.  
  877. ---------------------------------------------------------------------
  878.  
  879.  
  880. The problem is that we have the key that has been pressed in ah. How 
  881.  
  882. do we display it? We can't use function 9h because for that we need 
  883.  
  884. to have already defined the string which has to end with a dollar 
  885.  
  886. sign. This is what we do instead:
  887.  
  888.  
  889. ;after calling function 00h of interrupt 16h
  890.  
  891.  
  892. .mov dl,al               ;move al (ascii code) into dl
  893.  
  894. .mov ah,02h              ;function 02h of interrupt 21h
  895.  
  896. .int 21h                 ;call interrupt 21h
  897.  
  898.  
  899. If you want to save the value of AH then push AX before and pop it 
  900.  
  901. afterwards.
  902.  
  903.  
  904. CONTROL FLOW
  905.  
  906. ---------------------------------------------------------------------
  907.  
  908.  
  909. In assembly there is a set of commands for control flow like in any 
  910.  
  911. other language. Firstly the most basic command:
  912.  
  913. .
  914.  
  915. .jmp label 
  916.  
  917.  
  918. All this does it to move to the label specified and start executing 
  919.  
  920. the code there. For example:
  921.  
  922.  
  923. .jmp ALabel
  924.  
  925. ..
  926.  
  927. ..
  928.  
  929. ..     
  930.  
  931. .ALabel:
  932.  
  933.  
  934.  
  935. What do we do if we want to compare something? We have just got a 
  936.  
  937. key from the user but we want to do something with it. Lets print 
  938.  
  939. something out if it is equal to something else. How do we do that? 
  940.  
  941. It is easy. We use the jump on condition commands. Here is a list 
  942.  
  943. of them:
  944.  
  945.  
  946. JUMP ON CONDITION INSTRUCTIONS:
  947.  
  948.  
  949. JA      jumps if the first number was above the second number
  950.  
  951. JAE     same as above, but will also jump if they are equal
  952.  
  953. JB      jumps if the first number was below the second
  954.  
  955. JBE     same as above, but will also jump if they are equal
  956.  
  957. JNA     jumps if the first number was NOT above  (JBE)
  958.  
  959. JNAE    jumps if the first number was NOT above or the same as (JNB)
  960.  
  961. JNB     jumps if the first number was NOT below (JAE)
  962.  
  963. JNBE    jumps if the first number was NOT below or the same as (JA)     
  964.  
  965. JZ      jumps if the two numbers were equal
  966.  
  967. JE      same as JZ, just a different name
  968.  
  969. JNZ     jumps if the two numbers are NOT equal
  970.  
  971. JNE     same as above
  972.  
  973. JC      jump if carry flag is set
  974.  
  975. .
  976.  
  977. Note: the jump can only be a maximum of 127 bytes in either 
  978.  
  979. direction.
  980.  
  981.  
  982. Syntax:
  983.  
  984. .CMP register or variable, value
  985.  
  986. .jxx destination      
  987.  
  988.  
  989. An example of this is:
  990.  
  991.  
  992.       cmp al,'Y'      ;compare the value in al with Y
  993.  
  994.       je ItsYES       ;if it is equal then jump to ItsYES
  995.  
  996.  
  997. Every instruction takes up a certain amount of code space. You will 
  998.  
  999. get a warning if you try and jump over 127 bytes in either direction 
  1000.  
  1001. from the compiler. You can solve this by changing a sequence like this:
  1002.  
  1003.  
  1004. .cmp ax,10               ;is AX 10?
  1005.  
  1006. .je done                 ;yes, lets finish
  1007.  
  1008.  
  1009. to something like this:
  1010.  
  1011.  
  1012. .cmp ax,10               ;is AX 10?
  1013.  
  1014. .jne notdone             ;no it is not
  1015.  
  1016. .jmp done                ;we are now done
  1017.  
  1018. notdone:
  1019.  
  1020. .
  1021.  
  1022. This solves the problem but you may want to think about reordering 
  1023.  
  1024. your code or using procedures if this happens often.
  1025.  
  1026.  
  1027. Now we are going to look at a program which demonstrates input, 
  1028.  
  1029. output and control flow. 
  1030.  
  1031.  
  1032. Listing 2: PROGFLOW.ASM
  1033.  
  1034.  
  1035. ;a program to demonstrate program flow and input/output
  1036.  
  1037. .model tiny
  1038.  
  1039. .code                        
  1040.  
  1041. org 100h
  1042.  
  1043. start:
  1044.  
  1045.  
  1046. .mov dx,OFFSET Message   ;display a message on the screen
  1047.  
  1048. .mov ah,9                ;using function 09h
  1049.  
  1050. .int 21h                 ;of interrupt 21h
  1051.  
  1052.       
  1053.  
  1054. .mov dx,OFFSET Prompt    ;display a message on the screen  
  1055.  
  1056. .mov ah,9                ;using function 09h
  1057.  
  1058. .int 21h                 ;of interrupt 21h
  1059.  
  1060. .jmp First_Time
  1061.  
  1062.  
  1063. Prompt_Again:
  1064.  
  1065. .mov dx,OFFSET Another   ;display a message on the screen  
  1066.  
  1067. .mov ah,9                ;using function 09h
  1068.  
  1069. .int 21h                 ;of interrupt 21h
  1070.  
  1071.       
  1072.  
  1073. First_Time:
  1074.  
  1075.     mov dx,OFFSET Again         ;display a message on the screen  
  1076.  
  1077.     mov ah,9                    ;using function 09h
  1078.  
  1079.     int 21h                     ;of interrupt 21h
  1080.  
  1081.       
  1082.  
  1083.     xor ah,ah                   ;function 00h of
  1084.  
  1085.     int 16h                     ;interrupt 16h gets a character      
  1086.  
  1087.     mov bl,al                   ;save to bl 
  1088.  
  1089.       
  1090.  
  1091.     mov dl,al                   ;move al to dl
  1092.  
  1093.     mov ah,02h                  ;function 02h - display character
  1094.  
  1095.     int 21h                     ;call DOS service         
  1096.  
  1097.       
  1098.  
  1099.     cmp bl,'Y'                  ;is al=Y?
  1100.  
  1101.     je Prompt_Again             ;if yes then display it again
  1102.  
  1103.     cmp bl,'y'                  ;is al=y?
  1104.  
  1105.     je Prompt_Again             ;if yes then display it again
  1106.  
  1107.       
  1108.  
  1109. TheEnd:
  1110.  
  1111.     mov dx,OFFSET GoodBye       ;print goodbye message
  1112.  
  1113.     mov ah,9                    ;using function 9
  1114.  
  1115.     int 21h                     ;of interrupt 21h
  1116.  
  1117.     mov ah,4Ch                  ;terminate program DOSusing
  1118.  
  1119.     int 21h               
  1120.  
  1121.  
  1122. .DATA                            
  1123.  
  1124. CR  equ 13      ;enter                                  
  1125.  
  1126. LF  equ 10      ;line-feed
  1127.  
  1128.  
  1129. Message DB "A Simple Input/Output Program$"     
  1130.  
  1131. Prompt  DB CR,LF,"Here is your first prompt.$"     
  1132.  
  1133. Again   DB CR,LF,"Do you want to be prompted again? $"   
  1134.  
  1135. Another DB CR,LF,"Here is another prompt!$"    
  1136.  
  1137. GoodBye DB CR,LF,"Goodbye then.$"
  1138.  
  1139. end start
  1140.  
  1141.  
  1142. INTRODUCTION TO PROCEDURES
  1143.  
  1144. ---------------------------------------------------------------------
  1145.  
  1146.  
  1147. In assembly a procedure is the equivalent to a function in C or 
  1148.  
  1149. Pascal. A procedure provides a easy way to encapsulate some 
  1150.  
  1151. calculation which can then be used without worrying how it works. 
  1152.  
  1153. With procedures that are properly designed you can ignore how a 
  1154.  
  1155. job is done.
  1156.  
  1157.  
  1158. This is how a procedure is defined:
  1159.  
  1160.  
  1161. PROC AProcedure
  1162.  
  1163.     .
  1164.  
  1165.     .           ;some code to do something       
  1166.  
  1167.     .
  1168.  
  1169.     RET         ;if this is not here then your computer will crash                    
  1170.  
  1171. ENDP AProcedure
  1172.  
  1173.  
  1174. It is equally easy to run a procedure all you need to do is this:
  1175.  
  1176.  
  1177. .call AProcedure
  1178.  
  1179.  
  1180. This next program is an example of how to use a procedure. It is 
  1181.  
  1182. like the first example we looked at, all it does is print "Hello 
  1183.  
  1184. World!" on the screen.
  1185.  
  1186.  
  1187. Listing 3: SIMPPROC.ASM
  1188.  
  1189.  
  1190. ;This is a simple program to demonstrate procedures. It should 
  1191.  
  1192. ;print Hello World! on the screen when ran.
  1193.  
  1194.  
  1195. .model tiny 
  1196.  
  1197. .code 
  1198.  
  1199. org 100h
  1200.  
  1201.  
  1202. Start:                     
  1203.  
  1204. .call Display_Hi    ;Call the procedure
  1205.  
  1206. .mov ax,4C00h       ;return to DOS
  1207.  
  1208. .int 21h            ;interrupt 21h function 4Ch
  1209.  
  1210.  
  1211. Display_Hi PROC       
  1212.  
  1213. .mov dx,OFFSET HI   ;put offset of message into DX
  1214.  
  1215. .mov ah,9           ;function 9 - display string
  1216.  
  1217. .int 21h            ;call DOS service
  1218.  
  1219. .ret
  1220.  
  1221. Display_Hi ENDP       
  1222.  
  1223.  
  1224. HI      DB "Hello World!$" ;define a message
  1225.  
  1226.  
  1227. end Start
  1228.  
  1229.  
  1230.  
  1231. PROCEDURES THAT PASS PARAMETERS
  1232.  
  1233. ---------------------------------------------------------------------
  1234.  
  1235.  
  1236. Procedures wouldn't be so useful unless you could pass parameters to 
  1237.  
  1238. modify or use inside the procedure. There are three ways of doing 
  1239.  
  1240. this and I will cover all three methods: in registers, in memory and 
  1241.  
  1242. in the stack.
  1243.  
  1244.  
  1245. There are three example programs which all accomplish the same task. 
  1246.  
  1247. They print a square block (ASCII value 254) in a specified place. 
  1248.  
  1249. The sizes of the files when compiled are: 38 for register, 69 for 
  1250.  
  1251. memory and 52 for stack.
  1252.  
  1253.  
  1254. In registers
  1255.  
  1256. ---------------------------------------------------------------------
  1257.  
  1258.  
  1259. The advantages of this is that it is easy to do and is fast. All you 
  1260.  
  1261. have to do is to is move the parameters into registers before 
  1262.  
  1263. calling the procedure. 
  1264.  
  1265.  
  1266. Listing 4: PROC1.ASM
  1267.  
  1268.  
  1269. ;this a procedure to print a block on the screen using 
  1270.  
  1271. ;registers to pass parameters (cursor position of where to 
  1272.  
  1273. ;print it and colour).
  1274.  
  1275.  
  1276. .model tiny 
  1277.  
  1278. .code
  1279.  
  1280. org 100h
  1281.  
  1282. Start: 
  1283.  
  1284. .mov dh,4                ;row to print character on
  1285.  
  1286. .mov dl,5                ;column to print character on
  1287.  
  1288. .mov al,254              ;ascii value of block to display
  1289.  
  1290. .mov bl,4                ;colour to display character
  1291.  
  1292.  
  1293. .call PrintChar          ;print our character
  1294.  
  1295.  
  1296. .mov ax,4C00h            ;terminate program 
  1297.  
  1298. .int 21h
  1299.  
  1300.  
  1301. PrintChar PROC NEAR
  1302.  
  1303. .push cx                 ;save registers to be destroyed
  1304.  
  1305.  
  1306. .xor bh,bh               ;clear bh - video page 0
  1307.  
  1308. .mov ah,2                ;function 2 - move cursor
  1309.  
  1310. .int 10h                 ;row and col are already in dx
  1311.  
  1312.  
  1313. .pop bx                  ;restore bx
  1314.  
  1315. .xor bh,bh               ;display page - 0
  1316.  
  1317. .mov ah,9                ;function 09h write char & attrib
  1318.  
  1319. .mov cx,1                ;display it once
  1320.  
  1321. .int 10h                 ;call bios service
  1322.  
  1323.  
  1324. .pop cx                  ;restore registers
  1325.  
  1326. .ret                     ;return to where it was called
  1327.  
  1328. PrintChar ENDP
  1329.  
  1330.  
  1331. end Start
  1332.  
  1333.  
  1334. PASSING THROUGH MEMORY 
  1335.  
  1336. ---------------------------------------------------------------------
  1337.  
  1338.  
  1339. The advantages of this method is that it is easy to do but it makes 
  1340.  
  1341. your program larger and can be slower. 
  1342.  
  1343.  
  1344. To pass parameters through memory all you need to do is copy them to 
  1345.  
  1346. a variable which is stored in memory. You can use a variable in the 
  1347.  
  1348. same way that you can use a register but commands with registers are 
  1349.  
  1350. a lot faster.
  1351.  
  1352.  
  1353. Listing 5: PROC2.ASM    
  1354.  
  1355.  
  1356. ;this a procedure to print a block on the screen using memory 
  1357.  
  1358. ;to pass parameters (cursor position of where to print it and 
  1359.  
  1360. ;colour).
  1361.  
  1362.  
  1363. .model tiny 
  1364.  
  1365. .code
  1366.  
  1367. org 100h
  1368.  
  1369. Start: 
  1370.  
  1371.       mov Row,4                 ;row to print character
  1372.  
  1373.       mov Col,5                 ;column to print character on
  1374.  
  1375.       mov Char,254              ;ascii value of block to display
  1376.  
  1377.       mov Colour,4              ;colour to display character
  1378.  
  1379.  
  1380.       call PrintChar            ;print our character
  1381.  
  1382.  
  1383.       mov ax,4C00h              ;terminate program 
  1384.  
  1385.       int 21h
  1386.  
  1387.  
  1388. PrintChar PROC NEAR
  1389.  
  1390.       push ax cx bx             ;save registers to be destroyed
  1391.  
  1392.  
  1393.       xor bh,bh                 ;clear bh - video page 0
  1394.  
  1395.       mov ah,2                  ;function 2 - move cursor
  1396.  
  1397.       mov dh,Row
  1398.  
  1399.       mov dl,Col
  1400.  
  1401.       int 10h                   ;call Bios service           
  1402.  
  1403.  
  1404.       mov al,Char       
  1405.  
  1406.       mov bl,Colour
  1407.  
  1408.       xor bh,bh                 ;display page - 0
  1409.  
  1410.       mov ah,9                  ;function 09h write char & attrib 
  1411.  
  1412.       mov cx,1                  ;display it once
  1413.  
  1414.       int 10h                   ;call bios service
  1415.  
  1416.  
  1417.       pop bx cx ax            ;restore registers
  1418.  
  1419.       ret                     ;return to where it was called
  1420.  
  1421. PrintChar ENDP
  1422.  
  1423.  
  1424. Row     db ?    ;variables to store data
  1425.  
  1426. Col     db ?
  1427.  
  1428. Colour  db ?
  1429.  
  1430. Char    db ?
  1431.  
  1432.  
  1433. end Start
  1434.  
  1435.  
  1436. Passing through Stack
  1437.  
  1438. ---------------------------------------------------------------------
  1439.  
  1440.  
  1441. This is the most powerful and flexible method of passing parameters 
  1442.  
  1443. the problem is that it is more complicated.
  1444.  
  1445.  
  1446. Listing 6: PROC3.ASM
  1447.  
  1448.  
  1449. ;this a procedure to print a block on the screen using the 
  1450.  
  1451. ;stack to pass parameters (cursor position of where to print it 
  1452.  
  1453. ;and colour).
  1454.  
  1455.  
  1456. .model tiny 
  1457.  
  1458. .code
  1459.  
  1460. org 100h
  1461.  
  1462. Start: 
  1463.  
  1464. .mov dh,4                ;row to print string on
  1465.  
  1466. .mov dl,5                ;column to print string on
  1467.  
  1468. .mov al,254              ;ascii value of block to display
  1469.  
  1470. .mov bl,4                ;colour to display character
  1471.  
  1472.  
  1473. .push dx ax bx           ;put parameters onto the stack      
  1474.  
  1475. .call PrintString        ;print our string
  1476.  
  1477. .pop bx ax dx            ;restore registers
  1478.  
  1479.  
  1480. .mov ax,4C00h            ;terminate program 
  1481.  
  1482. .int 21h
  1483.  
  1484.  
  1485. PrintString PROC NEAR
  1486.  
  1487. .push bp                 ;save bp
  1488.  
  1489. .mov bp,sp               ;put sp into bp
  1490.  
  1491. .push cx                 ;save registers to be destroyed
  1492.  
  1493.  
  1494. .xor bh,bh               ;clear bh - video page 0
  1495.  
  1496. .mov ah,2                ;function 2 - move cursor
  1497.  
  1498. .mov dx,[bp+8]           ;restore dx
  1499.  
  1500. .int 10h                 ;call bios service
  1501.  
  1502.  
  1503. .mov ax,[bp+6]           ;character
  1504.  
  1505. .mov bx,[bp+4]           ;attribute
  1506.  
  1507. .xor bh,bh               ;display page - 0
  1508.  
  1509. .mov ah,9                ;function 09h write char & attrib 
  1510.  
  1511. .mov cx,1                ;display it once
  1512.  
  1513. .int 10h                 ;call bios service
  1514.  
  1515.  
  1516. .pop cx                  ;restore registers
  1517.  
  1518. .pop bp  
  1519.  
  1520. .ret                     ;return to where it was called
  1521.  
  1522. PrintString ENDP
  1523.  
  1524.  
  1525. end Start
  1526.  
  1527.  
  1528. To get a parameter from the stack all you need to do is work out 
  1529.  
  1530. where it is. The last parameter is at BP+2 and then the next and 
  1531.  
  1532. BP+4. 
  1533.  
  1534.  
  1535. WHAT ARE MEMORY MODELS?
  1536.  
  1537. ---------------------------------------------------------------------
  1538.  
  1539.  
  1540. We have been using the .MODEL directive to specify what type of 
  1541.  
  1542. memory model we  use, but what does this mean?
  1543.  
  1544.  
  1545. Syntax:
  1546.  
  1547. ..MODEL MemoryModel
  1548.  
  1549.  
  1550. Where MemoryModel can be SMALL, COMPACT, MEDIUM, LARGE, HUGE, TINY 
  1551.  
  1552. OR FLAT.
  1553.  
  1554.  
  1555. Tiny
  1556.  
  1557.  
  1558. This means that there is only one segment for both code and data. 
  1559.  
  1560. This type of program can be a .COM file.
  1561.  
  1562.  
  1563. Small
  1564.  
  1565.  
  1566. This means that by default all code is place in one segment and all 
  1567.  
  1568. data declared in the data segment is also placed in one segment. 
  1569.  
  1570. This means that all procedures and variables are addressed as NEAR 
  1571.  
  1572. by pointing at offsets only.
  1573.  
  1574.  
  1575. Compact
  1576.  
  1577.  
  1578. This means that by default all elements of code are placed in one 
  1579.  
  1580. segment but each element of data can be placed in its own physical 
  1581.  
  1582. segment. This means that data elements are addressed by pointing at 
  1583.  
  1584. both at the segment and offset addresses. Code elements (procedures) 
  1585.  
  1586. are NEAR and variables are FAR.
  1587.  
  1588.  
  1589. Medium
  1590.  
  1591.  
  1592. This is the opposite to compact. Data elements are NEAR and 
  1593.  
  1594. procedures are FAR.
  1595.  
  1596.  
  1597. Large
  1598.  
  1599.  
  1600. This means that both procedures and variables are FAR. You have to 
  1601.  
  1602. point at both the segment and offset addresses.
  1603.  
  1604.  
  1605. Flat
  1606.  
  1607.  
  1608. This isn't used much as it is for 32 bit unsegmented memory space. 
  1609.  
  1610. For this you need a DOS extender. This is what you would have to use 
  1611.  
  1612. if you were writing a program to interface with a C/C++ program that 
  1613.  
  1614. used a DOS extender such as DOS4GW or PharLap.
  1615.  
  1616.  
  1617. MACROS (in Turbo Assembler)
  1618.  
  1619. ---------------------------------------------------------------------
  1620.  
  1621.  
  1622. (All code examples given are for macros in Turbo Assembler.)
  1623.  
  1624.  
  1625. Macros are very useful for doing something that is done often but 
  1626.  
  1627. for which a procedure can't be use. Macros are substituted when the 
  1628.  
  1629. program is compiled to the code which they contain.
  1630.  
  1631.  
  1632. This is the syntax for defining a macro:
  1633.  
  1634.  
  1635. Name_of_macro   macro           
  1636.  
  1637. ;
  1638.  
  1639. ;a sequence of instructions 
  1640.  
  1641. ;
  1642.  
  1643. endm
  1644.  
  1645.  
  1646. These two examples are for macros that take away the boring job of 
  1647.  
  1648. pushing and popping certain registers:
  1649.  
  1650.  
  1651. .SaveRegs macro
  1652.  
  1653. ..pop ax
  1654.  
  1655. ..pop bx
  1656.  
  1657. ..pop cx
  1658.  
  1659. ..pop dx
  1660.  
  1661. .endm
  1662.  
  1663. .
  1664.  
  1665. .RestoreRegs macro
  1666.  
  1667. ..pop dx
  1668.  
  1669. ..pop cx
  1670.  
  1671. ..pop bx
  1672.  
  1673. ..pop ax
  1674.  
  1675. .
  1676.  
  1677. .endm
  1678.  
  1679.  
  1680. Note that the registers are popped in the reverse order to they were 
  1681.  
  1682. pushed. To use a macro in you program you just use the name of the 
  1683.  
  1684. macro as an ordinary instruction:
  1685.  
  1686.  
  1687. .SaveRegs
  1688.  
  1689. .;some other instructions
  1690.  
  1691. .RestoreRegs
  1692.  
  1693.  
  1694. This example shows how you can use a macro to save typing in. This 
  1695.  
  1696. macro simply prints out a message to the screen.
  1697.  
  1698.  
  1699. OutMsg  macro SomeText
  1700.  
  1701. .local PrintMe,SkipData
  1702.  
  1703. .jmp SkipData
  1704.  
  1705.  
  1706. PrintMe db SomeText,'$'
  1707.  
  1708.  
  1709. SkipData:
  1710.  
  1711.        push ax dx ds cs 
  1712.  
  1713.        pop ds
  1714.  
  1715.        mov dx,OFFSET cs:PrintMe
  1716.  
  1717.        mov ah,9
  1718.  
  1719.        int 21h
  1720.  
  1721.        pop ds dx ax
  1722.  
  1723. endm
  1724.  
  1725.  
  1726. endm
  1727.  
  1728.  
  1729. The only problems with macros is that if you overuse them it leads 
  1730.  
  1731. to you program getting bigger and bigger and that you have problems 
  1732.  
  1733. with multiple definition of labels and variables. The correct way to 
  1734.  
  1735. solve this problem is to use the LOCAL directive for declaring names 
  1736.  
  1737. inside macros.
  1738.  
  1739.  
  1740. Syntax:
  1741.  
  1742. .LOCAL name 
  1743.  
  1744.  
  1745. Where name is the name of a local variable or label.
  1746.  
  1747.  
  1748. Macros with parameters
  1749.  
  1750. ---------------------------------------------------------------------
  1751.  
  1752.  
  1753. Another useful property of macros is that they can have parameters. 
  1754.  
  1755. The number of parameters is only restricted by the length of the 
  1756.  
  1757. line. 
  1758.  
  1759.  
  1760. Syntax:
  1761.  
  1762.  
  1763. Name_of_Macro macro par1,par2,par3
  1764.  
  1765. ;
  1766.  
  1767. ;commands go here
  1768.  
  1769. ;
  1770.  
  1771. endm
  1772.  
  1773.  
  1774. This is an example that adds the first and second parameters and 
  1775.  
  1776. puts the result in the third:
  1777.  
  1778.  
  1779. .AddMacro macro num1,num2,result
  1780.  
  1781. ..push ax         ;save ax from being destroyed
  1782.  
  1783. ..mov ax,num1     ;put num1 into ax
  1784.  
  1785. ..add ax,num2     ;add num2 to it
  1786.  
  1787. ..mov result,ax   ;move answer into result
  1788.  
  1789. ..pop ax          ;restore ax
  1790.  
  1791. .endm
  1792.  
  1793.  
  1794.  
  1795. FILES AND HOW TO USE THEM
  1796.  
  1797. ---------------------------------------------------------------------
  1798.  
  1799.  
  1800. Files can be opened, read and written to. DOS has some ways of doing 
  1801.  
  1802. this which save us the trouble of writing our own routines. Yes, 
  1803.  
  1804. more interrupts. Here is a list of helpful functions of interrupt 
  1805.  
  1806. 21h that deal with files.
  1807.  
  1808.  
  1809. Note: Bits are numbered from right to left. 
  1810.  
  1811.  
  1812. Function 3Dh: open file
  1813.  
  1814.  
  1815. Opens an existing file for reading, writing or appending on the 
  1816.  
  1817. specified drive and filename.
  1818.  
  1819.  
  1820. INPUT:
  1821.  
  1822. .AH = 3Dh
  1823.  
  1824. .AL = bits 0-2   Access mode 
  1825.  
  1826. ..  000 = read only
  1827.  
  1828. ..  001 = write only
  1829.  
  1830. ..  010 = read/write
  1831.  
  1832. .     bits 4-6   Sharing mode (DOS 3+)
  1833.  
  1834. ..  000 = compatibility mode
  1835.  
  1836. ..  001 = deny all 
  1837.  
  1838. ..  010 = deny write 
  1839.  
  1840. ..  011 = deny read 
  1841.  
  1842. ..  100 = deny none 
  1843.  
  1844. .DS:DX = segment:offset of ASCIIZ pathname
  1845.  
  1846.  
  1847. OUTPUT:
  1848.  
  1849. .CF = 0 function is succesful
  1850.  
  1851. .AX = handle
  1852.  
  1853. .CF = 1 error has occured
  1854.  
  1855. .AX = error code
  1856.  
  1857. ..01h missing file sharing software
  1858.  
  1859. ..02h file not found
  1860.  
  1861. ..03h path not found or file does not exist
  1862.  
  1863. ..04h no handle available
  1864.  
  1865. ..05h access denied
  1866.  
  1867. ..0Ch access mode not permitted
  1868.  
  1869.  
  1870. What does ASCIIZ mean? An ASCIIZ string like a ASCII string with a 
  1871.  
  1872. zero on the end instead of a dollar sign.
  1873.  
  1874.  
  1875. Important: Remember to save the file handle it is needed for later.
  1876.  
  1877.  
  1878. How to save the file handle
  1879.  
  1880.  
  1881. It is important to save the file handle because this is needed to do 
  1882.  
  1883. anything with the file. Well how is this done? There are two methods 
  1884.  
  1885. we could use: copy the file handle into another register and don't 
  1886.  
  1887. use that register or copy it to a variable in memory.
  1888.  
  1889.  
  1890. The disadvantages with the first method is that you will have to 
  1891.  
  1892. remember not to use the register you saved it in and it wastes a 
  1893.  
  1894. register that can be used for something more useful. We are going to 
  1895.  
  1896. use the second. This is how it is done:
  1897.  
  1898.  
  1899. .FileHandle DW 0     ;use this for saving the file handle
  1900.  
  1901. ..
  1902.  
  1903. ..
  1904.  
  1905. ..
  1906.  
  1907. .mov FileHandle,ax   ;save the file handle
  1908.  
  1909.  
  1910. Function 3Eh: close file
  1911.  
  1912.  
  1913. Closes a file that has been opened.
  1914.  
  1915.  
  1916. INPUT:
  1917.  
  1918. .AX = 3Eh
  1919.  
  1920. .BX = file handle
  1921.  
  1922.  
  1923.  
  1924. OUTPUT:
  1925.  
  1926. .CF = 0 function is successful
  1927.  
  1928. .AX = destroyed
  1929.  
  1930. .CF = 1 function not successful
  1931.  
  1932. .AX = error code - 06h file not opened or unauthorised handle.
  1933.  
  1934.  
  1935. Important: Don't call this function with a zero handle because that 
  1936.  
  1937. will close the standard input (the keyboard) and you won't be able 
  1938.  
  1939. to enter anything.
  1940.  
  1941.        
  1942.  
  1943. Function 3Fh: read file/device
  1944.  
  1945.  
  1946. Reads bytes from a file or device to a buffer.
  1947.  
  1948.  
  1949. INPUT:
  1950.  
  1951. .AH = 3Fh
  1952.  
  1953. .BX = handle
  1954.  
  1955. .CX = number of bytes to be read
  1956.  
  1957. .DS:DX = segment:offset of a buffer
  1958.  
  1959.  
  1960. OUTPUT:
  1961.  
  1962. .CF = 0 function is successful
  1963.  
  1964. .AX = number of bytes read
  1965.  
  1966. .CF = 1 an error has occurred
  1967.  
  1968. ..05h access denied
  1969.  
  1970. ..06h illegal handle or file not opened
  1971.  
  1972.  
  1973. If CF = 0 and AX = 0 then the file pointer was already at the end of 
  1974.  
  1975. the file and no more can be read. If CF = 0 and AX is smaller than 
  1976.  
  1977. CX then only part was read because the end of the file was reached 
  1978.  
  1979. or an error occurred. 
  1980.  
  1981.  
  1982. This function can also be used to get input from the keyboard. Use a 
  1983.  
  1984. handle of 0, and it stops reading after the first carriage return, 
  1985.  
  1986. or once a specified number of characters have been read. This is a 
  1987.  
  1988. good and easy method to use to only let the user enter a certain 
  1989.  
  1990. amount of characters.
  1991.  
  1992.  
  1993. Listing 7: READFILE.ASM
  1994.  
  1995.  
  1996. ;a program to demonstrate creating a file and then writing to 
  1997.  
  1998. ;it
  1999.  
  2000.  
  2001. .model small
  2002.  
  2003. .stack
  2004.  
  2005. .code                
  2006.  
  2007.  
  2008. .mov ax,@data            ;base address of data segment
  2009.  
  2010. .mov ds,ax               ;put this in ds
  2011.  
  2012. .
  2013.  
  2014. .mov dx,OFFSET FileName  ;put address of filename in dx        
  2015.  
  2016.         mov al,2                ;access mode - read and write
  2017.  
  2018. .mov ah,3Dh              ;function 3Dh -open a file
  2019.  
  2020. .int 21h                 ;call DOS service
  2021.  
  2022.         mov Handle,ax           ;save file handle for later
  2023.  
  2024. .jc ErrorOpening         ;jump if carry flag set - error!
  2025.  
  2026. .
  2027.  
  2028. .mov dx,offset Buffer    ;address of buffer in dx
  2029.  
  2030. .mov bx,Handle           ;handle in bx
  2031.  
  2032. .mov cx,100              ;amount of bytes to be read
  2033.  
  2034. .mov ah,3Fh              ;function 3Fh - read from file
  2035.  
  2036. .int 21h                 ;call dos service
  2037.  
  2038.         jc ErrorReading         ;jump if carry flag set - error!  
  2039.  
  2040.  
  2041. .mov bx,Handle           ;put file handle in bx 
  2042.  
  2043.         mov ah,3Eh              ;function 3Eh - close a file
  2044.  
  2045.         int 21h                 ;call DOS service
  2046.  
  2047. .   
  2048.  
  2049.         mov cx,100              ;length of string
  2050.  
  2051.         mov si,OFFSET Buffer    ;DS:SI - address of string
  2052.  
  2053. .xor bh,bh               ;video page - 0
  2054.  
  2055.         mov ah,0Eh              ;function 0Eh - write character
  2056.  
  2057.  
  2058. NextChar:
  2059.  
  2060. .lodsb                   ;AL = next character in string
  2061.  
  2062.         int 10h                 ;call BIOS service
  2063.  
  2064. .loop NextChar
  2065.  
  2066.  
  2067. .mov ax,4C00h            ;terminate program                                                                        
  2068.  
  2069.         int 21h          
  2070.  
  2071.  
  2072. ErrorOpening:
  2073.  
  2074.       mov dx,offset OpenError   ;display an error                                                                            
  2075.  
  2076.       mov ah,09h                ;using function 09h
  2077.  
  2078.       int 21h                   ;call DOS service
  2079.  
  2080.       mov ax,4C01h              ;end program with an errorlevel =1   
  2081.  
  2082.       int 21h   
  2083.  
  2084. ..
  2085.  
  2086. ErrorReading:
  2087.  
  2088.       mov dx,offset ReadError   ;display an error                                                                            
  2089.  
  2090.       mov ah,09h                ;using function 09h
  2091.  
  2092.       int 21h                   ;call DOS service
  2093.  
  2094. ..
  2095.  
  2096.       mov ax,4C02h              ;end program with an errorlevel =2   
  2097.  
  2098.       int 21h
  2099.  
  2100.  
  2101.  
  2102. .data
  2103.  
  2104.  
  2105. Handle        DW ?                      ;to store file handle   
  2106.  
  2107. FileName      DB "C:\test.txt",0        ;file to be opened
  2108.  
  2109.  
  2110. OpenError     DB "An error has occured(opening)!$"
  2111.  
  2112. ReadError     DB "An error has occured(reading)!$"
  2113.  
  2114.  
  2115. Buffer        DB 100 dup (?)            ;buffer to store data
  2116.  
  2117.  
  2118. END
  2119.  
  2120.  
  2121.  
  2122. Function 3Ch: Create file
  2123.  
  2124.  
  2125. Creates a new empty file on a specified drive with a specified pathname.
  2126.  
  2127.  
  2128. INPUT:
  2129.  
  2130. .AH = 3Ch
  2131.  
  2132. .CX = file attribute
  2133.  
  2134. ..bit 0 = 1 read-only file
  2135.  
  2136. ..bit 1 = 1 hidden file
  2137.  
  2138. ..bit 2 = 1 system file
  2139.  
  2140. ..bit 3 = 1 volume (ignored)
  2141.  
  2142. ..bit 4 = 1 reserved (0) - directory
  2143.  
  2144. ..bit 5 = 1 archive bit
  2145.  
  2146. ..bits 6-15 reserved (0)
  2147.  
  2148.     DS:DX = segment:offset of ASCIIZ pathname
  2149.  
  2150.  
  2151. OUTPUT:
  2152.  
  2153.     CF = 0 function is successful
  2154.  
  2155.     AX = handle
  2156.  
  2157.     CF = 1 an error has occurred
  2158.  
  2159. ..03h path not found
  2160.  
  2161. ..04h no available handle
  2162.  
  2163. ..05h access denied
  2164.  
  2165.  
  2166. Important: If a file of the same name exists then it will be lost. 
  2167.  
  2168. Make sure that there is no file of the same name. This can be done 
  2169.  
  2170. with the function below.
  2171.  
  2172.  
  2173. Function 4Eh: find first matching file
  2174.  
  2175.  
  2176. Searches for the first file that matches the filename given.
  2177.  
  2178.  
  2179. INPUT:
  2180.  
  2181.     AH = 4Eh
  2182.  
  2183.     CX = file attribute mask (bits can be combined)
  2184.  
  2185. ..bit 0 = 1 read only
  2186.  
  2187. ..bit 1 = 1 hidden
  2188.  
  2189. ..bit 2 = 1 system
  2190.  
  2191. ..bit 3 = 1 volume label
  2192.  
  2193. ..bit 4 = 1 directory
  2194.  
  2195. ..bit 5 = 1 archive
  2196.  
  2197. ..bit 6-15 reserved
  2198.  
  2199.     DS:DX = segment:offset of ASCIIZ pathname
  2200.  
  2201.  
  2202. OUTPUT:
  2203.  
  2204.     CF = 0 function is successful
  2205.  
  2206.     [DTA] Disk Transfer Area = FindFirst data block
  2207.  
  2208.  
  2209. The DTA block
  2210.  
  2211.  
  2212. Offset      Size in bytes     Meaning
  2213.  
  2214.  
  2215. 0               21            Reserved
  2216.  
  2217. 21              1             File attributes
  2218.  
  2219. 22              2             Time last modified
  2220.  
  2221. 24              2             Date last modified
  2222.  
  2223. 26              4             Size of file (in bytes)
  2224.  
  2225. 30              13            File name (ASCIIZ)
  2226.  
  2227.  
  2228. An example of checking if file exists:
  2229.  
  2230.  
  2231. File    DB "C:\file.txt",0      ;name of file that we want
  2232.  
  2233.  
  2234. .mov dx,OFFSET File      ;address of filename
  2235.  
  2236. .mov cx,3Fh              ;file mask 3Fh - any file
  2237.  
  2238. .mov ah,4Eh              ;function 4Eh - find first file
  2239.  
  2240. .int 21h                 ;call DOS service
  2241.  
  2242. .jc NoFile
  2243.  
  2244. .
  2245.  
  2246. .;print message saying file exists
  2247.  
  2248. NoFile:
  2249.  
  2250. .;continue with creating file
  2251.  
  2252.  
  2253. This is an example of creating a file and then writing to it.
  2254.  
  2255.  
  2256. Listing 8: CREATE.ASM
  2257.  
  2258.  
  2259. ;This example program creates a file and then writes to it.
  2260.  
  2261.  
  2262. .model small
  2263.  
  2264. .stack
  2265.  
  2266. .code               
  2267.  
  2268.  
  2269.      mov ax,@data       ;base address of data segment
  2270.  
  2271.      mov ds,ax          ;put it in ds
  2272.  
  2273.  
  2274.      mov dx,offset StartMessage ;display the starting message 
  2275.  
  2276.      mov ah,09h                 ;using function 09h
  2277.  
  2278.      int 21h                    ;call dos service
  2279.  
  2280.  
  2281.  
  2282.      mov dx,offset FileName     ;put offset of filename in dx        
  2283.  
  2284.      xor cx,cx                  ;clear cx - make ordinary file
  2285.  
  2286.      mov ah,3Ch                 ;function 3Ch - create a file
  2287.  
  2288.      int 21h                    ;call DOS service
  2289.  
  2290.      jc CreateError             ;jump if there is an error
  2291.  
  2292. .
  2293.  
  2294.      mov dx,offset FileName     ;put offset of filename in dx
  2295.  
  2296.      mov al,2                   ;access mode -read and write
  2297.  
  2298.      mov ah,3Dh                 ;function 3Dh - open the file
  2299.  
  2300.      int 21h                    ;call dos service
  2301.  
  2302.      jc OpenError               ;jump if there is an error
  2303.  
  2304.      mov Handle,ax              ;save value of handle        
  2305.  
  2306.  
  2307.      mov dx,offset WriteMe      ;address of information to write 
  2308.  
  2309.      mov bx,Handle              ;file handle for file
  2310.  
  2311.      mov cx,38                  ;38 bytes to be written
  2312.  
  2313.      mov ah,40h                 ;function 40h - write to file
  2314.  
  2315.      int 21h                    ;call dos service
  2316.  
  2317.      jc WriteError              ;jump if there is an error
  2318.  
  2319.      cmp ax,cx                  ;was all the data written?
  2320.  
  2321.      jne WriteError             ;no it wasn't - error!
  2322.  
  2323.  
  2324.      mov bx,Handle              ;put file handle in bx 
  2325.  
  2326.      mov ah,3Eh                 ;function 3Eh - close a file
  2327.  
  2328.      int 21h                    ;call dos service
  2329.  
  2330. .
  2331.  
  2332.      mov dx,offset EndMessage   ;display the final message 
  2333.  
  2334.      mov ah,09h                 ;using function 09h
  2335.  
  2336.      int 21h                    ;call dos service
  2337.  
  2338.  
  2339.  
  2340. ReturnToDOS:
  2341.  
  2342.      mov ax,4C00h               ;terminate program 
  2343.  
  2344.      int 21h                    
  2345.  
  2346.  
  2347. WriteError:
  2348.  
  2349.      mov dx,offset WriteMessage ;display an error message 
  2350.  
  2351.      jmp EndError
  2352.  
  2353.  
  2354. OpenError:
  2355.  
  2356.      mov dx,offset OpenMessage  ;display an error message 
  2357.  
  2358.      jmp EndError
  2359.  
  2360.  
  2361. CreateError:
  2362.  
  2363.      mov dx,offset CreateMessage  ;display an error message 
  2364.  
  2365.  
  2366. EndError:
  2367.  
  2368.      mov ah,09h                         ;using function 09h
  2369.  
  2370.      int 21h                            ;call dos service
  2371.  
  2372.      mov ax,4C01h                       ;terminate program 
  2373.  
  2374.      int 21h                            
  2375.  
  2376.  
  2377. .data                            
  2378.  
  2379.  
  2380. CR      equ     13
  2381.  
  2382. LF      equ     10
  2383.  
  2384.  
  2385. StartMessage    DB "This program creates a file called NEW.TXT"                         DB ,"on the C drive.$"
  2386.  
  2387. EndMessage      DB CR,LF,"File create OK, look at file to"                      DB ,"be sure.$"
  2388.  
  2389.  
  2390. WriteMessage  DB "An error has occurred (WRITING)$"
  2391.  
  2392. OpenMessage   DB "An error has occurred (OPENING)$"
  2393.  
  2394. CreateMessage DB "An error has occurred (CREATING)$"
  2395.  
  2396.  
  2397. WriteMe         DB "HELLO, THIS IS A TEST, HAS IT WORKED?",0  
  2398.  
  2399.  
  2400. FileName        DB "C:\new.txt",0         ;name of file to open                              
  2401.  
  2402. Handle          DW ?                      ;to store file handle   
  2403.  
  2404.  
  2405. END
  2406.  
  2407.  
  2408. This is an example of how to delete a file after checking it exists:
  2409.  
  2410.  
  2411. Listing 9: DELFILE.ASM
  2412.  
  2413.  
  2414. ;a demonstration of how to delete a file. The file new.txt on 
  2415.  
  2416. ;c: is deleted (this file is created by create.exe). We also 
  2417.  
  2418. ;check if the file exits before trying to delete it
  2419.  
  2420.  
  2421. .model small
  2422.  
  2423. .stack
  2424.  
  2425. .data
  2426.  
  2427.  
  2428. CR      equ 13
  2429.  
  2430. LF      equ 10
  2431.  
  2432.  
  2433. File    db "C:\new.txt",0 
  2434.  
  2435.  
  2436. Deleted db "Deleted file c:\new.txt$"
  2437.  
  2438. NoFile  db "c:\new.txt doesn't exits - exiting$"
  2439.  
  2440. ErrDel  db "Can't delete file - probably write protected$"
  2441.  
  2442.  
  2443. .code
  2444.  
  2445. .mov ax,@data            ;set up ds as the segment for data
  2446.  
  2447. .mov ds,ax               ;use ax as we can't do it directly
  2448.  
  2449.  
  2450. .mov dx,OFFSET File      ;address of filename to look for
  2451.  
  2452.         mov cx,3Fh              ;file mask 3Fh - any file
  2453.  
  2454. .mov ah,4Eh              ;function 4Eh - find first file
  2455.  
  2456. .int 21h                 ;call dos service
  2457.  
  2458. .jc FileDontExist
  2459.  
  2460.  
  2461.         mov dx,OFFSET File      ;DS:DX points to file to be killed                        
  2462.  
  2463.         mov ah,41h              ;function 41h - delete file
  2464.  
  2465.         int 21h                 ;call DOS service
  2466.  
  2467.         jc ErrorDeleting        ;jump if there was an error
  2468.  
  2469.  
  2470. .jmp EndOk
  2471.  
  2472.  
  2473. EndOk:
  2474.  
  2475. .mov dx,OFFSET Deleted   ;display message 
  2476.  
  2477.         jmp Endit
  2478.  
  2479.  
  2480. ErrorDeleting:
  2481.  
  2482. .mov dx,OFFSET ErrDel    ;display message 
  2483.  
  2484. .jmp Endit
  2485.  
  2486.  
  2487. FileDontExist:
  2488.  
  2489. .mov dx,OFFSET NoFile    ;display message 
  2490.  
  2491.  
  2492. EndIt:
  2493.  
  2494. .mov ah,9
  2495.  
  2496. .int 21h
  2497.  
  2498. .
  2499.  
  2500. .mov ax,4C00h            ;terminate program and exit to DOS
  2501.  
  2502. .int 21h                 ;call DOS service
  2503.  
  2504.  
  2505. end
  2506.  
  2507.  
  2508. USING THE FINDFIRST AND FINDNEXT FUNCTIONS
  2509.  
  2510. ---------------------------------------------------------------------
  2511.  
  2512.  
  2513. Listing 10: DIRC.ASM
  2514.  
  2515.  
  2516. ;this program demonstrates how to look for files. It prints
  2517.  
  2518. ;out the names of all the files in the c:\drive and names of
  2519.  
  2520. ;the sub-directories
  2521.  
  2522.  
  2523. .model small
  2524.  
  2525. .stack
  2526.  
  2527. .data
  2528.  
  2529.  
  2530. FileName db "c:\*.*",0          ;file name
  2531.  
  2532. DTA      db 128 dup(?)          ;buffer to store the DTA       
  2533.  
  2534. ErrorMsg db "An Error has occurred - exiting.$"
  2535.  
  2536.  
  2537. .code
  2538.  
  2539.      mov ax,@data               ;set up ds to be equal to the 
  2540.  
  2541.      mov ds,a                   ;data segment
  2542.  
  2543.      mov es,ax                  ;also es
  2544.  
  2545. ...
  2546.  
  2547.      mov dx,OFFSET DTA          ;DS:DX points to DTA             
  2548.  
  2549.      mov ah,1AH                 ;function 1Ah - set DTA
  2550.  
  2551.      int 21h                    ;call DOS service
  2552.  
  2553.  
  2554.      mov cx,3Fh                 ;attribute mask - all files
  2555.  
  2556.      mov dx,OFFSET FileName     ;DS:DX points ASCIZ filename
  2557.  
  2558.      mov ah,4Eh                 ;function 4Eh - find first
  2559.  
  2560.      int 21h                    ;call DOS service
  2561.  
  2562.      jc error                   ;jump if carry flag is set
  2563.  
  2564.  
  2565. LoopCycle:
  2566.  
  2567.      mov dx,OFFSET FileName     ;DS:DX points to file name
  2568.  
  2569.      mov ah,4Fh                 ;function 4fh - find next
  2570.  
  2571.      int 21h                    ;call DOS service
  2572.  
  2573.      jc exit                    ;exit if carry flag is set
  2574.  
  2575.  
  2576.  
  2577.      mov cx,13                  ;length of filename
  2578.  
  2579.      mov si,OFFSET DTA+30       ;DS:SI points to filename in DTA
  2580.  
  2581.      xor bh,bh                  ;video page - 0
  2582.  
  2583.      mov ah,0Eh                 ;function 0Eh - write character
  2584.  
  2585.  
  2586. NextChar:
  2587.  
  2588.      lodsb                      ;AL = next character in string
  2589.  
  2590.      int 10h                    ;call BIOS service
  2591.  
  2592.      loop NextChar
  2593.  
  2594.  
  2595.      mov di,OFFSET DTA+30       ;ES:DI points to DTA
  2596.  
  2597.      mov cx,13                  ;length of filename
  2598.  
  2599.      xor al,al                  ;fill with zeros
  2600.  
  2601.      rep stosb                  ;erase DTA
  2602.  
  2603.  
  2604.      jmp LoopCycle              ;continue searching
  2605.  
  2606.  
  2607. error:                          
  2608.  
  2609. .mov dx,OFFSET ErrorMsg  ;display error message
  2610.  
  2611. .mov ah,9
  2612.  
  2613. .int 21h
  2614.  
  2615. exit:
  2616.  
  2617. .mov ax,4C00h            ;exit to DOS
  2618.  
  2619. .int 21h
  2620.  
  2621.  
  2622. end
  2623.  
  2624.  
  2625. STRING INSTRUCTIONS
  2626.  
  2627. ---------------------------------------------------------------------
  2628.  
  2629.  
  2630. In assembly there are some very useful instructions for dealing with 
  2631.  
  2632. strings. Here is a list of the instructions and the syntax for using 
  2633.  
  2634. them:
  2635.  
  2636.  
  2637. MOV*       Move String: moves byte, word or double word at DS:SI 
  2638.  
  2639.            to ES:DI
  2640.  
  2641.  
  2642. Syntax:
  2643.  
  2644.  
  2645. .movsb           ;move byte
  2646.  
  2647. .movsw           ;move word
  2648.  
  2649. .movsd           ;move double word
  2650.  
  2651.  
  2652. CMPS*       Compare string: compares byte, word or double word at 
  2653.  
  2654.             DS:SI to ES:DI
  2655.  
  2656.  
  2657. Syntax:
  2658.  
  2659.  
  2660. .cmpsb           ;compare byte
  2661.  
  2662. .cmpsw           ;compare word
  2663.  
  2664. .cmpsd           ;compare double word
  2665.  
  2666.  
  2667. Note: This instruction is normally used with the REP prefix. 
  2668.  
  2669.  
  2670. SCAS* Search string: search for AL, AX, or EAX in string at ES:DI
  2671.  
  2672.  
  2673. Syntax:
  2674.  
  2675. .
  2676.  
  2677. .scasb           ;search for AL
  2678.  
  2679. .scasw           ;search for AX
  2680.  
  2681. .scasd           ;search for EAX
  2682.  
  2683.  
  2684. Note: This instruction is usually used with the REPZ or REPNZ prefix.
  2685.  
  2686.  
  2687. REP     Prefix for string instruction repeats instruction CX times
  2688.  
  2689.  
  2690. Syntax:
  2691.  
  2692.  
  2693. .rep StringInstruction
  2694.  
  2695.  
  2696. STOS*  Move byte, word or double word from AL, AX or EAX to ES:DI
  2697.  
  2698.  
  2699. Syntax:
  2700.  
  2701. .
  2702.  
  2703. .stosb           ;move AL into ES:DI
  2704.  
  2705. .stosw           ;move AX into ES:DI
  2706.  
  2707. .stosd           ;move EAX into ES:DI
  2708.  
  2709.  
  2710.  
  2711. LODS* Move byte, word or double word from DS:SI to AL, AX or EAX
  2712.  
  2713.  
  2714. Syntax:
  2715.  
  2716.  
  2717. .lodsb           ;move ES:DI into AL
  2718.  
  2719. .lodsw           ;move ES:DI into AX
  2720.  
  2721. .lodsd           ;move ES:DI into EAX
  2722.  
  2723. .
  2724.  
  2725. Listing 11: STRINGS.ASM
  2726.  
  2727.  
  2728. ;This program demonstrates string examples
  2729.  
  2730.  
  2731. .model small
  2732.  
  2733. .stack
  2734.  
  2735. .code 
  2736.  
  2737.  
  2738.       mov ax,@data              ;ax points to of data segment
  2739.  
  2740.       mov ds,ax                 ;put it into ds
  2741.  
  2742.       mov es,ax                 ;put it in es too
  2743.  
  2744. .
  2745.  
  2746.       mov ah,9                  ;function 9 - display string
  2747.  
  2748.       mov dx,OFFSET Message1    ;ds:dx points to message
  2749.  
  2750.       int 21h                   ;call dos function
  2751.  
  2752.  
  2753.       cld                       ;clear direction flag
  2754.  
  2755.  
  2756.       mov si,OFFSET String1     ;make ds:si point to String1
  2757.  
  2758.       mov di,OFFSET String2     ;make es:di point to String2
  2759.  
  2760.       mov cx,18                 ;length of strings
  2761.  
  2762.       rep movsb                 ;copy string1 into string2
  2763.  
  2764.     
  2765.  
  2766.       mov ah,9                  ;function 9 - display string
  2767.  
  2768.       mov dx,OFFSET Message2    ;ds:dx points to message
  2769.  
  2770.       int 21h                   ;call dos function
  2771.  
  2772. .
  2773.  
  2774.       mov dx,OFFSET String1     ;display String1
  2775.  
  2776.       int 21h                   ;call DOS service
  2777.  
  2778. .
  2779.  
  2780.       mov dx,OFFSET Message3    ;ds:dx points to message
  2781.  
  2782.       int 21h                   ;call dos function
  2783.  
  2784. .
  2785.  
  2786.       mov dx,OFFSET String2     ;display String2
  2787.  
  2788.       int 21h                   ;call DOS service
  2789.  
  2790.  
  2791.       mov si,OFFSET Diff1       ;make ds:si point to Diff1  
  2792.  
  2793.       mov di,OFFSET Diff2       ;make es:di point to Diff2  
  2794.  
  2795.       mov cx,39                 ;length of strings
  2796.  
  2797.       repz cmpsb                ;compare strings
  2798.  
  2799.       jnz Not_Equal             ;jump if they are not the same
  2800.  
  2801. .
  2802.  
  2803.       mov ah,9                  ;function 9 - display string
  2804.  
  2805.       mov dx,OFFSET Message4    ;ds:dx points to message
  2806.  
  2807.       int 21h                   ;call dos function
  2808.  
  2809. .
  2810.  
  2811.       jmp Next_Operation
  2812.  
  2813.  
  2814. Not_Equal:
  2815.  
  2816. .mov ah,9                ;function 9 - display string
  2817.  
  2818. .mov dx,OFFSET Message5  ;ds:dx points to message
  2819.  
  2820. .int 21h                 ;call dos function
  2821.  
  2822. .
  2823.  
  2824. Next_Operation:
  2825.  
  2826. .mov di,OFFSET SearchString ;make es:di point to string
  2827.  
  2828. .mov cx,36               ;length of string
  2829.  
  2830. .mov al,'H'              ;character to search for
  2831.  
  2832. .repne scasb             ;find first match
  2833.  
  2834. .jnz Not_Found
  2835.  
  2836.  
  2837. .mov ah,9                ;function 9 - display string
  2838.  
  2839. .mov dx,OFFSET Message6  ;ds:dx points to message
  2840.  
  2841. .int 21h                 ;call dos function
  2842.  
  2843.  
  2844. .jmp Lodsb_Example
  2845.  
  2846.  
  2847. Not_Found:
  2848.  
  2849. .mov ah,9                ;function 9 - display string
  2850.  
  2851. .mov dx,OFFSET Message7  ;ds:dx points to message
  2852.  
  2853. .int 21h                 ;call dos function
  2854.  
  2855.  
  2856. Lodsb_Example:
  2857.  
  2858. .mov ah,9                ;function 9 - display string
  2859.  
  2860. .mov dx,OFFSET NewLine   ;ds:dx points to message
  2861.  
  2862. .int 21h                 ;call dos function
  2863.  
  2864.  
  2865. .mov cx,17               ;length of string
  2866.  
  2867.         mov si,OFFSET Message   ;DS:SI - address of string
  2868.  
  2869.         xor bh,bh               ;video page - 0
  2870.  
  2871. .mov ah,0Eh              ;function 0Eh - write character
  2872.  
  2873. NextChar:
  2874.  
  2875.       lodsb                     ;AL = next character in string
  2876.  
  2877.       int 10h                   ;call BIOS service
  2878.  
  2879.       loop NextChar
  2880.  
  2881.  
  2882.       mov ax,4C00h              ;return to DOS
  2883.  
  2884.       int 21h               
  2885.  
  2886.  
  2887. .data
  2888.  
  2889.  
  2890. CR equ 13
  2891.  
  2892. LF equ 10
  2893.  
  2894.  
  2895. String1 db "This is a string!$"
  2896.  
  2897. String2 db 18 dup(0)
  2898.  
  2899.  
  2900. Diff1   db "This string is nearly the same as Diff2$"
  2901.  
  2902. Diff2   db "This string is nearly the same as Diff1$"
  2903.  
  2904.  
  2905. Equal1  db "The strings are equal$"
  2906.  
  2907. Equal2  db "The strings are not equal$"
  2908.  
  2909.  
  2910. SearchString db "1293ijdkfjiu938uHello983fjkfjsi98934$"
  2911.  
  2912.  
  2913.  
  2914. Message db "This is a message"
  2915.  
  2916.  
  2917. Message1 db "Using String instructions example program.$"
  2918.  
  2919. Message2 db CR,LF,"String1 is now: $"
  2920.  
  2921. Message3 db CR,LF,"String2 is now: $"
  2922.  
  2923. Message4 db CR,LF,"Strings are equal!$"
  2924.  
  2925. Message5 db CR,LF,"Strings are not equal!$"
  2926.  
  2927. Message6 db CR,LF,"Character was found.$"
  2928.  
  2929. Message7 db CR,LF,"Character was not found.$"
  2930.  
  2931.  
  2932. NewLine  db CR,LF,"$"
  2933.  
  2934.  
  2935. end 
  2936.  
  2937.  
  2938. HOW TO FIND OUT THE DOS VERSION
  2939.  
  2940. ---------------------------------------------------------------------
  2941.  
  2942.  
  2943. In many programs it is necessary to find out what the DOS version 
  2944.  
  2945. is. This could be because you are using a DOS function that needs 
  2946.  
  2947. the revision to be over a certain level.
  2948.  
  2949.  
  2950. Firstly this method simply finds out what the version is.
  2951.  
  2952.  
  2953. .mov     ah,30h          ;function 30h - get MS-DOS version
  2954.  
  2955. .int     21h             ;call DOS function
  2956.  
  2957.  
  2958. This function returns the major version number in AL and the minor 
  2959.  
  2960. version number in AH. For example if it was version 4.01, AL would 
  2961.  
  2962. be 4 and AH would be 01. The problem is that if on DOS 5 and higher 
  2963.  
  2964. SETVER can change the version that is returned. The way to get round 
  2965.  
  2966. this is to use this method.
  2967.  
  2968.  
  2969. .mov     ah,33h          ;function 33h - actual DOS version
  2970.  
  2971. .mov     al,06h          ;subfunction 06h
  2972.  
  2973. .int     21h             ;call interrupt 21h     
  2974.  
  2975.  
  2976. This will only work on DOS version 5 and above so you need to check 
  2977.  
  2978. using the former method. This will return the actual version of DOS 
  2979.  
  2980. even if SETVER has changed the version. This returns the major 
  2981.  
  2982. version in BL and the minor version in BH.
  2983.  
  2984.  
  2985. MULTIPLE PUSHES AND POPS
  2986.  
  2987. ---------------------------------------------------------------------
  2988.  
  2989.  
  2990. You can push and pop more than one register on a line in TASM and 
  2991.  
  2992. A86. This makes your code easier to understand.
  2993.  
  2994.  
  2995. .push ax bx cx dx                ;save registers
  2996.  
  2997. .pop dx cx bx ax                 ;restore registers
  2998.  
  2999.  
  3000. When TASM (or A86) compiles these lines it translates it into 
  3001.  
  3002. separate pushes an pops. This way just saves you time typing and 
  3003.  
  3004. makes it easier to understand.
  3005.  
  3006.  
  3007. Note: To make these lines compile in A86 you need to put commas (,) 
  3008.  
  3009. in between the registers.
  3010.  
  3011.  
  3012. THE PUSHA/PUSHAD AND POPA/POPAD INSTRUCTIONS
  3013.  
  3014. ---------------------------------------------------------------------
  3015.  
  3016.  
  3017. PUSHA is a useful instruction that pushes all general purpose 
  3018.  
  3019. registers onto the stack. It accomplishes the same as the following:
  3020.  
  3021.  
  3022. .temp = SP
  3023.  
  3024. .push ax
  3025.  
  3026. .push cx
  3027.  
  3028. .push dx
  3029.  
  3030. .push bx
  3031.  
  3032. .push temp
  3033.  
  3034. .push bp
  3035.  
  3036. .push si
  3037.  
  3038. .push di
  3039.  
  3040.  
  3041. The main advantage is that it is less typing, a smaller instruction 
  3042.  
  3043. and it is a lot faster. POPA does the reverse and pops these 
  3044.  
  3045. registers off the stack. PUSHAD and POPAD do the same but with the 
  3046.  
  3047. 32-bit registers ESP, EAX, ECX, EDX, EBX, EBP, ESI and EDI.
  3048.  
  3049.  
  3050. USING SHIFTS FOR FASTER MULTIPLICATION AND DIVISION
  3051.  
  3052. ---------------------------------------------------------------------
  3053.  
  3054.  
  3055. Using MUL's and DIV's is very slow and should be only used when 
  3056.  
  3057. speed is not needed. For faster multiplication and division you can 
  3058.  
  3059. shift numbers left or right one or more binary positions. Each shift 
  3060.  
  3061. is to a power of 2. This is the same as the << and >> operators in 
  3062.  
  3063. C. There are four different ways of shifting numbers either left or 
  3064.  
  3065. right one binary position. 
  3066.  
  3067.  
  3068. SHL Unsigned multiple by two
  3069.  
  3070. SHR Unsigned divide by two
  3071.  
  3072. SAR Signed divide by two
  3073.  
  3074. SAL same as SHL
  3075.  
  3076.  
  3077. The syntax for all four is the same.
  3078.  
  3079.  
  3080. Syntax:
  3081.  
  3082. SHL operand1,operand2
  3083.  
  3084.  
  3085. Note: The 8086 cannot have the value of opperand2 other than 1. 
  3086.  
  3087. 286/386 cannot have operand2 higher than 31.
  3088.  
  3089.  
  3090. LOOPS
  3091.  
  3092. ---------------------------------------------------------------------
  3093.  
  3094.  
  3095. Using Loop is a better way of making a loop then using JMP's. You 
  3096.  
  3097. place the amount of times you want it to loop in the CX register and 
  3098.  
  3099. every time it reaches the loop statement it decrements CX (CX-1) and 
  3100.  
  3101. then does a short jump to the label indicated. A short jump means 
  3102.  
  3103. that it can only 128 bytes before or 127 bytes after the LOOP 
  3104.  
  3105. instruction. 
  3106.  
  3107.  
  3108. Syntax:
  3109.  
  3110. .mov cx,100                      ;100 times to loop
  3111.  
  3112. Label:
  3113.  
  3114. ..
  3115.  
  3116. ..       
  3117.  
  3118. ..
  3119.  
  3120. .Loop Label:             ;decrement CX and loop to Label
  3121.  
  3122.  
  3123. This is exactly the same as the following piece of code without 
  3124.  
  3125. using loop:
  3126.  
  3127.  
  3128. .mov cx,100                      ;100 times to loop
  3129.  
  3130. Label:
  3131.  
  3132. .dec cx                  ;CX = CX-1
  3133.  
  3134. .jnz Label                       ;continue until done
  3135.  
  3136.  
  3137. Which do you think is easier to understand? Using DEC/JNZ is faster 
  3138.  
  3139. on 486's and above and it is useful as you don't have to use CX.
  3140.  
  3141.  
  3142. This works because JNZ will jump if the zero flag has not been set. 
  3143.  
  3144. Setting CX to 0 will set this flag.
  3145.  
  3146.  
  3147. HOW TO USE A DEBUGGER
  3148.  
  3149. ---------------------------------------------------------------------
  3150.  
  3151.  
  3152. This is a good time to use a debugger to find out what your program 
  3153.  
  3154. is actually doing. I am going to demonstrate how to use Turbo 
  3155.  
  3156. Debugger to check what the program is actually doing. First we need 
  3157.  
  3158. a program which we can look at.
  3159.  
  3160.  
  3161. Listing 12: DEBUG.ASM
  3162.  
  3163.  
  3164. ;example program to demonstrate how to use a debugger
  3165.  
  3166.  
  3167. .model tiny        
  3168.  
  3169. .code
  3170.  
  3171. org 100h
  3172.  
  3173. start:
  3174.  
  3175.  
  3176. .push ax                 ;save value of ax
  3177.  
  3178. .push bx                 ;save value of bx
  3179.  
  3180. .push cx                 ;save value of cx
  3181.  
  3182. .
  3183.  
  3184. .mov ax,10               ;first parameter is 10                  
  3185.  
  3186. .mov bx,20               ;second parameter is 20
  3187.  
  3188. .mov cx,3                ;third parameter is 3
  3189.  
  3190. .
  3191.  
  3192. .Call ChangeNumbers      ;call procedure
  3193.  
  3194. .
  3195.  
  3196. .pop cx                  ;restore cx
  3197.  
  3198. .pop bx                  ;restore bx
  3199.  
  3200. .pop ax                  ;restore dx
  3201.  
  3202.  
  3203. .mov ax,4C00h            ;exit to dos
  3204.  
  3205. .int 21h 
  3206.  
  3207.  
  3208. ChangeNumbers PROC      
  3209.  
  3210. .add ax,bx               ;adds number in bx to ax
  3211.  
  3212. .mul cx                  ;multiply ax by cx
  3213.  
  3214. .mov dx,ax               ;return answer in dx
  3215.  
  3216. .ret
  3217.  
  3218. ChangeNumbers ENDP      
  3219.  
  3220.  
  3221. end start
  3222.  
  3223.  
  3224. Now compile it to a .COM file and then type:
  3225.  
  3226.  
  3227. .td name of file
  3228.  
  3229.  
  3230. Turbo Debugger then loads. You can see the instructions that make up 
  3231.  
  3232. your programs, for example the first few lines of this program is 
  3233.  
  3234. shown as:
  3235.  
  3236. .
  3237.  
  3238. .cs:0000 50              push   ax
  3239.  
  3240. .cs:0001 53              push   bx
  3241.  
  3242. .cs:0002 51              push   cx
  3243.  
  3244.  
  3245. Some useful keys for Turbo Debugger:
  3246.  
  3247.  
  3248. F5              Size Window
  3249.  
  3250. F7              Next Instruction
  3251.  
  3252. F9              Run
  3253.  
  3254. ALT F4          Step Backwards
  3255.  
  3256.  
  3257. .
  3258.  
  3259. The numbers that are moved into the registers are different that the 
  3260.  
  3261. ones that in the source code because they are represented in their 
  3262.  
  3263. hex form (base 16) as this is the easiest base to convert to and 
  3264.  
  3265. from binary and that it is easier to understand than binary also. 
  3266.  
  3267.  
  3268. At the left of this display there is a box showing the contents of 
  3269.  
  3270. the registers. At this time all the main registers are empty. Now 
  3271.  
  3272. press F7 this means that the first line of the program is run. As 
  3273.  
  3274. the first line pushed the AX register into the stack, you can see 
  3275.  
  3276. that the stack pointer (SP) has changed. Press F7 until the line 
  3277.  
  3278. which contains mov ax,000A is highlighted. Now press it again. Now 
  3279.  
  3280. if you look at the box which contains the contents of the registers 
  3281.  
  3282. you can see that AX contains A. Press it again and BX now contains 
  3283.  
  3284. 14, press it again and CX contains 3. Now if you press F7 again you 
  3285.  
  3286. can see that AX now contains 1E which is A+14. Press it again and 
  3287.  
  3288. now AX contains 5A 1E multiplied by 3. Press F7 again and you will 
  3289.  
  3290. see that DX now also contains 5A. Press it three more times and you 
  3291.  
  3292. can see that CX, BX and AX are all set back to their original values 
  3293.  
  3294. of zero.
  3295.  
  3296.  
  3297. MORE OUTPUT IN TEXT MODES
  3298.  
  3299. ---------------------------------------------------------------------
  3300.  
  3301.  
  3302. I am going to cover some more ways of outputting text in text modes. 
  3303.  
  3304. This first program is an example of how to move the cursor to 
  3305.  
  3306. display a string of text where you want it to go.
  3307.  
  3308.  
  3309. Listing 12: TEXT1.ASM
  3310.  
  3311.  
  3312. .model tiny 
  3313.  
  3314. .code
  3315.  
  3316. org 100h
  3317.  
  3318. start:
  3319.  
  3320. .mov dh,12               ;cursor col   
  3321.  
  3322. .mov dl,32               ;cursor row
  3323.  
  3324. .mov ah,02h              ;move cursor to the right place
  3325.  
  3326. .xor bh,bh               ;video page 0
  3327.  
  3328. .int 10h                 ;call bios service
  3329.  
  3330.  
  3331. .mov dx,OFFSET Text      ;DS:DX points to message
  3332.  
  3333. .mov ah,9                ;function 9 - display string
  3334.  
  3335. .int 21h                 ;call dos service
  3336.  
  3337.  
  3338. .mov ax,4C00h            ;exit to dos
  3339.  
  3340. .int 21h
  3341.  
  3342.  
  3343. Text    DB "This is some text$" 
  3344.  
  3345.  
  3346. This next example demonstrates how to write to the screen using the 
  3347.  
  3348. file function 40h of interrupt 21h.
  3349.  
  3350.  
  3351. Listing 13: TEXT2.ASM
  3352.  
  3353.  
  3354. end start
  3355.  
  3356. .model small
  3357.  
  3358. .stack
  3359.  
  3360. .code
  3361.  
  3362. .mov ax,@data            ;set up ds as the segment for data
  3363.  
  3364. .mov ds,ax               ;put this in ds
  3365.  
  3366. .
  3367.  
  3368. .mov ah,40h              ;function 40h - write file
  3369.  
  3370. .mov bx,1                ;handle = 1 (screen)
  3371.  
  3372. .mov cx,17               ;length of string
  3373.  
  3374. .mov dx,OFFSET Text      ;DS:DX points to string
  3375.  
  3376. .int 21h                 ;call DOS service
  3377.  
  3378. .
  3379.  
  3380. .mov ax,4C00h            ;terminate program
  3381.  
  3382. .int 21h
  3383.  
  3384.  
  3385. .data
  3386.  
  3387.  
  3388. Text    DB "This is some text"
  3389.  
  3390.  
  3391. end
  3392.  
  3393.  
  3394. The next program shows how to set up and call function 13h of 
  3395.  
  3396. interrupt 10h - write string. This has the advantages of being able 
  3397.  
  3398. to write a string anywhere on the screen in a specified colour but 
  3399.  
  3400. it is hard to set up.
  3401.  
  3402.  
  3403. Listing 14: TEXT3.ASM
  3404.  
  3405.  
  3406. .model small
  3407.  
  3408. .stack
  3409.  
  3410. .code
  3411.  
  3412. .mov ax,@data            ;set up ds as the segment for data
  3413.  
  3414. .mov es,ax               ;put this in es
  3415.  
  3416. .mov bp,OFFSET Text      ;ES:BP points to message
  3417.  
  3418.  
  3419. .mov ah,13h              ;function 13 - write string
  3420.  
  3421. .mov al,01h              ;attrib in bl,move cursor
  3422.  
  3423. .xor bh,bh               ;video page 0
  3424.  
  3425. .mov bl,5                ;attribute - magenta
  3426.  
  3427. .mov cx,17               ;length of string
  3428.  
  3429. .mov dh,5                ;row to put string
  3430.  
  3431. .mov dl,5                ;column to put string
  3432.  
  3433. .int 10h                 ;call BIOS service
  3434.  
  3435. .
  3436.  
  3437. .mov ax,4C00h            ;return to DOS
  3438.  
  3439. .int 21h
  3440.  
  3441.  
  3442. .data
  3443.  
  3444.  
  3445. Text    DB "This is some text"
  3446.  
  3447. end
  3448.  
  3449.  
  3450. The next program demonstrates how to write to the screen using rep 
  3451.  
  3452. stosw to put the writing in video memory. 
  3453.  
  3454.  
  3455. Listing 15: TEXT4.ASM
  3456.  
  3457.  
  3458. .model small
  3459.  
  3460. .stack
  3461.  
  3462. .code
  3463.  
  3464. .mov ax,0B800h           ;segment of video buffer
  3465.  
  3466. .mov es,ax               ;put this into es
  3467.  
  3468. .xor di,di               ;clear di, ES:DI points to video memory
  3469.  
  3470. .mov ah,4                ;attribute - red
  3471.  
  3472. .mov al,"G"              ;character to put there
  3473.  
  3474. .mov cx,4000             ;amount of times to put it there 
  3475.  
  3476. .cld                     ;direction - forwards
  3477.  
  3478. .rep stosw               ;output character at ES:[DI]
  3479.  
  3480. .
  3481.  
  3482. .mov ax,4C00h            ;return to DOS
  3483.  
  3484. .int 21h
  3485.  
  3486.  
  3487. end
  3488.  
  3489.  
  3490.  
  3491. The next program demonstrates how to write a string to video memory.
  3492.  
  3493.  
  3494. Listing 15: DIRECTWR.ASM
  3495.  
  3496.  
  3497. ;write a string direct to video memory 
  3498.  
  3499.  
  3500. .model small
  3501.  
  3502. .stack
  3503.  
  3504. .code
  3505.  
  3506. .mov ax,@data
  3507.  
  3508. .mov ds,ax
  3509.  
  3510. .
  3511.  
  3512. .mov ax,0B800h           ;segment of video buffer
  3513.  
  3514. .mov es,ax               ;put this into es
  3515.  
  3516. .
  3517.  
  3518. .mov ah,3                ;attribute - cyan
  3519.  
  3520. .mov cx,17               ;length of string to print
  3521.  
  3522. .mov si,OFFSET Text      ;DX:SI points to string
  3523.  
  3524. .xor di,di
  3525.  
  3526.  
  3527. Wr_Char:
  3528.  
  3529. .lodsb                   ;put next character into al        
  3530.  
  3531. .mov es:[di],al          ;output character to video memory
  3532.  
  3533. .inc di                  ;move along to next column
  3534.  
  3535. .mov es:[di],ah          ;output attribute to video memory
  3536.  
  3537. .inc di
  3538.  
  3539. .loop Wr_Char            ;loop until done
  3540.  
  3541. .
  3542.  
  3543. .mov ax,4C00h            ;return to DOS
  3544.  
  3545. .int 21h
  3546.  
  3547. .
  3548.  
  3549. .data
  3550.  
  3551.  
  3552. Text    DB "This is some text"   
  3553.  
  3554.  
  3555. end
  3556.  
  3557.  
  3558. It is left as an exercise to the reader to modify it so that only 
  3559.  
  3560. one write is made to video memory. 
  3561.  
  3562.  
  3563. MODE 13h
  3564.  
  3565. ---------------------------------------------------------------------
  3566.  
  3567.  
  3568. Mode 13h is only available on VGA, MCGA cards and above. The reason 
  3569.  
  3570. that I am talking about this card is that it is very easy to use for 
  3571.  
  3572. graphics because of how the memory is arranged.
  3573.  
  3574.  
  3575. FIRST CHECK THAT MODE 13h IS POSSIBLE
  3576.  
  3577. ---------------------------------------------------------------------
  3578.  
  3579.  
  3580. It would be polite to tell the user if his/her computer cannot 
  3581.  
  3582. support mode 13h instead of just crashing his computer without 
  3583.  
  3584. warning. This is how it is done.
  3585.  
  3586.  
  3587. Listing 16: CHECK13.ASM
  3588.  
  3589.  
  3590. .model small
  3591.  
  3592. .stack
  3593.  
  3594. .data
  3595.  
  3596.  
  3597. NoSupport       db "Mode 13h is not supported on this computer."
  3598.  
  3599. ..db ,"You need either a MCGA or VGA video"                               db ,"card/monitor.$"
  3600.  
  3601. Supported       db "Mode 13h is supported on this computer.$"
  3602.  
  3603.  
  3604. .code
  3605.  
  3606.  
  3607. .mov ax,@data            ;set up DS to point to data segment
  3608.  
  3609. .mov ds,ax               ;use ax 
  3610.  
  3611.  
  3612. .call Check_Mode_13h     ;check if mode 13h is possible
  3613.  
  3614. .jc Error                ;if cf=1 there is an error
  3615.  
  3616.  
  3617. .mov ah,9                ;function 9 - display string
  3618.  
  3619. .mov dx,OFFSET Supported ;DS:DX points to message
  3620.  
  3621. .int 21h                 ;call DOS service
  3622.  
  3623.  
  3624. .jmp To_DOS              ;exit to DOS
  3625.  
  3626.  
  3627. Error:
  3628.  
  3629. .mov ah,9                ;function 9 - display string
  3630.  
  3631. .mov dx,OFFSET NoSupport ;DS:DX points to message
  3632.  
  3633. .int 21h                 ;call DOS service
  3634.  
  3635.  
  3636. To_DOS:
  3637.  
  3638. .mov ax,4C00h            ;exit to DOS 
  3639.  
  3640. .int 21h
  3641.  
  3642.  
  3643. Check_Mode_13h PROC             ;Returns: CF = 1 Mode 13h not possible
  3644.  
  3645. .
  3646.  
  3647. .mov ax,1A00h            ;Request video info for VGA
  3648.  
  3649. .int 10h                 ;Get Display Combination Code
  3650.  
  3651. .cmp al,1Ah              ;Is VGA or MCGA present?
  3652.  
  3653. .je Mode_13h_OK          ;mode 13h is supported
  3654.  
  3655. .stc                     ;mode 13h isn't supported CF=1
  3656.  
  3657.  
  3658. Mode_13h_OK:
  3659.  
  3660. .ret                     
  3661.  
  3662.  
  3663. Check_Mode_13h ENDP
  3664.  
  3665.  
  3666. end 
  3667.  
  3668.  
  3669. Just use this to check if mode 13h is supported at the beginning of 
  3670.  
  3671. your program to make sure that you can go into that mode.
  3672.  
  3673.  
  3674. SETTING THE VIDEO MODE
  3675.  
  3676. ---------------------------------------------------------------------
  3677.  
  3678.  
  3679. It is very simple to set the mode. This is how it is done.
  3680.  
  3681.  
  3682. .mov  ax,13h                     ;set mode 13h
  3683.  
  3684. .int  10h                        ;call BIOS service
  3685.  
  3686.  
  3687. Once we are in mode 13h and have finished what we are doing we need 
  3688.  
  3689. to we need to set it to the video mode that it was in previously. 
  3690.  
  3691. This is done in two stages. Firstly we need to save the video mode 
  3692.  
  3693. and then reset it to that mode.
  3694.  
  3695.  
  3696. VideoMode db ?
  3697.  
  3698. ....
  3699.  
  3700. .mov ah,0Fh                      ;function 0Fh - get current mode
  3701.  
  3702. .int 10h                         ;Bios video service call
  3703.  
  3704. .mov VideoMode,al                ;save current mode
  3705.  
  3706.  
  3707. .;program code here
  3708.  
  3709.  
  3710. .mov al,VideoMode                ;set previous video mode
  3711.  
  3712. .xor ah,ah                       ;clear ah - set mode
  3713.  
  3714. .int 10h                         ;call bios service
  3715.  
  3716. .mov ax,4C00h                    ;exit to dos
  3717.  
  3718. .int 21h                         ;call dos function
  3719.  
  3720.  
  3721. Now that we can get into mode 13h lets do something. Firstly lets 
  3722.  
  3723. put some pixels on the screen. 
  3724.  
  3725.  
  3726. Function 0Ch: Write Graphics Pixel
  3727.  
  3728.  
  3729. This makes a colour dot on the screen at the specified graphics 
  3730.  
  3731. coordinates.
  3732.  
  3733.  
  3734. INPUT:
  3735.  
  3736. .AH = 0Ch
  3737.  
  3738. .AL = Color of the dot
  3739.  
  3740. .CX = Screen column (x coordinate)
  3741.  
  3742. .DX = Screen row (y coordinate)
  3743.  
  3744.  
  3745. OUTPUT:
  3746.  
  3747. .Nothing except pixel on screen.
  3748.  
  3749.  
  3750. Note: This function performs exclusive OR (XOR) with the new colour 
  3751.  
  3752. value and the current context of the pixel of bit 7 of AL is set.
  3753.  
  3754.  
  3755. This program demonstrates how to plot pixels. It should plot four 
  3756.  
  3757. red pixels into the middle of the screen.
  3758.  
  3759.  
  3760. Listing 17: PIXINT.ASM
  3761.  
  3762.  
  3763. ;example of plotting pixels in mode 13 using bios services - 
  3764.  
  3765. ;INT 10h
  3766.  
  3767.  
  3768. .model tiny
  3769.  
  3770. .code
  3771.  
  3772. org 100h
  3773.  
  3774.  
  3775. start:
  3776.  
  3777. .mov ax,13               ;mode = 13h                      
  3778.  
  3779. .int 10h                 ;call bios service
  3780.  
  3781.  
  3782. .mov ah,0Ch              ;function 0Ch
  3783.  
  3784. .mov al,4                ;color 4 - red
  3785.  
  3786. .mov cx,160              ;x position = 160
  3787.  
  3788. .mov dx,100              ;y position = 100
  3789.  
  3790. .int 10h                 ;call BIOS service
  3791.  
  3792. .
  3793.  
  3794. .inc dx                  ;plot pixel downwards
  3795.  
  3796. .int 10h                 ;call BIOS service
  3797.  
  3798. .inc cx                  ;plot pixel to right
  3799.  
  3800. .int 10h                 ;call BIOS service
  3801.  
  3802. .dec dx                  ;plot pixel up
  3803.  
  3804. .int 10h                 ;call BIOS service
  3805.  
  3806.  
  3807. .xor ax,ax               ;function 00h - get a key
  3808.  
  3809. .int 16h                 ;call BIOS service
  3810.  
  3811. .mov ax,3                ;mode = 3
  3812.  
  3813. .int 10h                 ;call BIOS service
  3814.  
  3815.  
  3816. .mov ax,4C00h            ;exit to DOS
  3817.  
  3818. .int 21h
  3819.  
  3820.  
  3821. end start
  3822.  
  3823.  
  3824. SOME OPTIMIZATIONS
  3825.  
  3826. ---------------------------------------------------------------------
  3827.  
  3828.  
  3829. This method isn't too fast and we could make it a lot faster. How? 
  3830.  
  3831. By writing direct to video memory. This is done quite easily. 
  3832.  
  3833.  
  3834. The VGA segment is 0A000h. To work out where each pixel goes you use 
  3835.  
  3836. this simple formula to get the offset.
  3837.  
  3838.  
  3839. .Offset = X + ( Y x 320 )
  3840.  
  3841.  
  3842. All we do is to put a number at this location and there is now a 
  3843.  
  3844. pixel on the screen. The number is what colour it is.
  3845.  
  3846.  
  3847. There are two instructions that we can use to put a pixel on the 
  3848.  
  3849. screen, firstly we could use stosb to put the value in AL to ES:DI 
  3850.  
  3851. or we can use a new form of the MOV instruction like this:
  3852.  
  3853.  
  3854. .mov es:[di], color
  3855.  
  3856.  
  3857. Which should we use? When we are going to write pixels to the screen 
  3858.  
  3859. we need to do so as fast as it is possible. 
  3860.  
  3861.  
  3862. Instruction             Pentium     486     386     286     86
  3863.  
  3864.  
  3865. STOSB                   3           5       4       3       11
  3866.  
  3867. MOV AL to SEG:OFF       1           1       4       3       10
  3868.  
  3869.  
  3870. If you use the MOV method you may need to increment DI (which STOSB 
  3871.  
  3872. does).
  3873.  
  3874.  
  3875. [ put pixel instruction]
  3876.  
  3877.  
  3878. If we had a program which used sprites which need to be continuously 
  3879.  
  3880. draw, erased and then redraw you will have problems with flicker. To 
  3881.  
  3882. avoid this you can use a 'double buffer'. This is another part of 
  3883.  
  3884. memory which you write to and then copy all the information onto the 
  3885.  
  3886. screen. 
  3887.  
  3888.